测试一:使用member function创建action会产生gc,不管该函数是否访问外部变量:

    private System.Action memberAct = null;
// gc 112B
private void ActionWithMethod()
{
memberAct = new System.Action(LocalMethod);
}
// gc 112B, if LocalMethod() is static, then no gc
private void ActionWithMethod2()
{
memberAct = LocalMethod;
}
// no gc
private void ActionWithMethod3()
{
System.Action act = memberAct;
}
private void LocalMethod()
{
foreach (var item in lst)
Debug.Log(item);
}

  ActionWithMethod和ActionWithMethod2是等效的,gc值如下所示:

  

  IL代码也一摸一样:

  

  所以将一个member function复制给一个action会产生gc,解决的办法就是ActionWithMethod3,也就是用一个actin member缓存起来,然后将缓存的action member复制给新建的action,这样只会产生一次gc:

  如果将LocalMethod设置为static函数,则ActionWithMethod2也不会产生gc:
    private static void LocalMethod()
{
}

  

测试二:使用匿名函数,如果访问了外部变量,也会产生gc;如果不访问外部变量,则只产生一次gc

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestAnonymousFunctionGC : MonoBehaviour
{
private System.Action actMember = null;
private int iMember = ;
public TestAnonymousFunctionGC()
{
}
private void Update()
{
UnityEngine.Profiling.Profiler.BeginSample("*** AnoymousFunctionWithoutArg ***");
AnoymousFunctionWithoutArg();
UnityEngine.Profiling.Profiler.EndSample();
UnityEngine.Profiling.Profiler.BeginSample("*** AnoymousFunctionWithMemberArg ***");
AnoymousFunctionWithMemberArg();
UnityEngine.Profiling.Profiler.EndSample();
UnityEngine.Profiling.Profiler.BeginSample("*** AnoymousFunctionWithLocalArg1 ***");
AnoymousFunctionWithLocalArg1();
UnityEngine.Profiling.Profiler.EndSample();
UnityEngine.Profiling.Profiler.BeginSample("*** AnoymousFunctionWithLocalArg2 ***");
AnoymousFunctionWithLocalArg2();
UnityEngine.Profiling.Profiler.EndSample();
UnityEngine.Profiling.Profiler.BeginSample("*** AnoymousFunctionWithLocalArg3 ***");
AnoymousFunctionWithLocalArg3();
UnityEngine.Profiling.Profiler.EndSample();
}
// no gc
private void AnoymousFunctionWithoutArg()
{
actMember = () => { };
}
// gc 112B
private void AnoymousFunctionWithMemberArg()
{
actMember = () =>
{
Debug.Log(iMember);
};
}
// gc 129B
private void AnoymousFunctionWithLocalArg1()
{
bool bValue = true;
actMember = () =>
{
Debug.Log(bValue);
};
}
// gc 132B
private void AnoymousFunctionWithLocalArg2()
{
int iValue = ;
actMember = () =>
{
Debug.Log(iValue);
};
}
// gc 136B
private void AnoymousFunctionWithLocalArg3()
{
int iValue = ;
int iValue2 = ;
actMember = () =>
{
Debug.Log(iValue);
Debug.Log(iValue2);
};
}
}

  

  同时还可以发现,匿名函数引用的外部变量的个数会影响gc的值,为什么呢?来分析一波:

  

  可以看到访问外部变量的匿名函数,会导致临时对象的创建,这样会导致gc,那位为什么每个临时变量的gc值不一样呢,我们来看一下这些临时class的定义:

  

  可以看匿名函数所访问的外部变量都会在临时类里面创建一个拷贝,这样每个类对象的大小就不一样了。

  附上类型定义的完整代码,前因后果一目了然:

public class TestAnonymousFunctionGC : MonoBehaviour
{
// Fields
private Action actMember;
private int iMember; // Methods
public TestAnonymousFunctionGC()
{
this.actMember = null;
this.iMember = ;
base..ctor();
return;
} [CompilerGenerated]
private void <AnoymousFunctionWithMemberArg>b__5_0()
{
Debug.Log((int) this.iMember);
return;
} private void AnoymousFunctionWithLocalArg1()
{
<>c__DisplayClass6_0 class_;
class_ = new <>c__DisplayClass6_0();
class_.bValue = ;
this.actMember = new Action(class_.<AnoymousFunctionWithLocalArg1>b__0);
return;
} private void AnoymousFunctionWithLocalArg2()
{
<>c__DisplayClass7_0 class_;
class_ = new <>c__DisplayClass7_0();
class_.iValue = ;
this.actMember = new Action(class_.<AnoymousFunctionWithLocalArg2>b__0);
return;
} private void AnoymousFunctionWithLocalArg3()
{
<>c__DisplayClass8_0 class_;
class_ = new <>c__DisplayClass8_0();
class_.iValue = ;
class_.iValue2 = ;
this.actMember = new Action(class_.<AnoymousFunctionWithLocalArg3>b__0);
return;
} private void AnoymousFunctionWithMemberArg()
{
this.actMember = new Action(this.<AnoymousFunctionWithMemberArg>b__5_0);
return;
} private void AnoymousFunctionWithoutArg()
{
this.actMember = (<>c.<>9__4_0 != null) ? <>c.<>9__4_0 : (<>c.<>9__4_0 = new Action(this.<AnoymousFunctionWithoutArg>b__4_0));
return;
} private void Update()
{
Profiler.BeginSample("*** AnoymousFunctionWithoutArg ***");
this.AnoymousFunctionWithoutArg();
Profiler.EndSample();
Profiler.BeginSample("*** AnoymousFunctionWithMemberArg ***");
this.AnoymousFunctionWithMemberArg();
Profiler.EndSample();
Profiler.BeginSample("*** AnoymousFunctionWithLocalArg1 ***");
this.AnoymousFunctionWithLocalArg1();
Profiler.EndSample();
Profiler.BeginSample("*** AnoymousFunctionWithLocalArg2 ***");
this.AnoymousFunctionWithLocalArg2();
Profiler.EndSample();
Profiler.BeginSample("*** AnoymousFunctionWithLocalArg3 ***");
this.AnoymousFunctionWithLocalArg3();
Profiler.EndSample();
return;
} // Nested Types
[Serializable, CompilerGenerated]
private sealed class <>c
{
// Fields
public static readonly TestAnonymousFunctionGC.<>c <>;
public static Action <>9__4_0; // Methods
static <>c()
{
<> = new TestAnonymousFunctionGC.<>c();
return;
} public <>c()
{
base..ctor();
return;
} internal void <AnoymousFunctionWithoutArg>b__4_0()
{
return;
}
} [CompilerGenerated]
private sealed class <>c__DisplayClass6_0
{
// Fields
public bool bValue; // Methods
public <>c__DisplayClass6_0()
{
base..ctor();
return;
} internal void <AnoymousFunctionWithLocalArg1>b__0()
{
Debug.Log((bool) this.bValue);
return;
}
} [CompilerGenerated]
private sealed class <>c__DisplayClass7_0
{
// Fields
public int iValue; // Methods
public <>c__DisplayClass7_0()
{
base..ctor();
return;
} internal void <AnoymousFunctionWithLocalArg2>b__0()
{
Debug.Log((int) this.iValue);
return;
}
} [CompilerGenerated]
private sealed class <>c__DisplayClass8_0
{
// Fields
public int iValue;
public int iValue2; // Methods
public <>c__DisplayClass8_0()
{
base..ctor();
return;
} internal void <AnoymousFunctionWithLocalArg3>b__0()
{
Debug.Log((int) this.iValue);
Debug.Log((int) this.iValue2);
return;
}
}
} Collapse Methods

参考:https://blog.uwa4d.com/archives/Anonymous_heapmemory.html

Vector3.Equals函数会有gc:

        // Vector3.Equeals有GC 28B
{
UnityEngine.Profiling.Profiler.BeginSample("*** Vector3.Equals ***");
Vector3 dir1 = Vector3.one, dir2 = Vector3.one;
var equals = dir1.Equals(dir2);
UnityEngine.Profiling.Profiler.EndSample();
}

匿名函数gc分析的更多相关文章

  1. Javascript闭包和C#匿名函数对比分析

    C#中引入匿名函数,多少都是受到Javascript的闭包语法和面向函数编程语言的影响.人们发现,在表达式中直接编写函数代码是一种普遍存在的需求,这种语法将比那种必须在某个特定地方定义函数的方式灵活和 ...

  2. python——内置函数和匿名函数

    内置函数 接下来,我们就一起来看看python里的内置函数.截止到python版本3.6.2,现在python一共为我们提供了68个内置函数.它们就是python提供给你直接可以拿来使用的所有函数.这 ...

  3. Python_匿名函数_47

    匿名函数 Eva_J 匿名函数:为了解决那些功能很简单的需求而设计的一句话函数 #这段代码 def calc(n): return n**n print(calc(10)) #换成匿名函数 calc ...

  4. python----内置函数2与匿名函数

    1.迭代器生成器相关 range:创建一个可迭代对象,一般与for混合使用,可设置步长. for i in range(0,10,2): #步长2范围为0-10不包括10 print(i) # 0 2 ...

  5. python全栈开发之匿名函数和递归函数

    python 匿名函数和递归函数 python全栈开发,匿名函数,递归函数 匿名函数 lambda函数也叫匿名函数,即函数没有具体的名称.是为了解决一些功能很简单需求而设计的一句话函数.如下: #这段 ...

  6. python——内置函数和lambda匿名函数

    内置函数 接下来,我们就一起来看看python里的内置函数.截止到python版本3.6.2,现在python一共为我们提供了68个内置函数.它们就是python提供给你直接可以拿来使用的所有函数.这 ...

  7. Python— 匿名函数

    匿名函数 匿名函数:为了解决那些功能很简单的需求而设计的  “一句话函数” #初始代码 def calc(n): return n**n print(calc(10)) #换成匿名函数 calc = ...

  8. python之路——内置函数和匿名函数

    阅读目录 楔子 内置函数 匿名函数 本章小结 楔子 在讲新知识之前,我们先来复习复习函数的基础知识. 问:函数怎么调用? 函数名() 如果你们这么说...那你们就对了!好了记住这个事儿别给忘记了,咱们 ...

  9. python 内置函数和匿名函数

    内置函数 截止到python版本3.6.2,现在python一共为我们提供了68个内置函数.     Built-in Functions     abs() dict() help() min() ...

随机推荐

  1. Java 8 (二) 新的时间API

    新的时间API 一)时间线 Instant对象:表示时间轴上的一个点,原点为1970-1-1的午夜. Duration对象:表示一段时间. 注意Instant和Duration类都是final. 二) ...

  2. php 生成xml文件

    <?php class Xml{        /*      *  $aData     要格式化的数组      *  $path      xml信息要写入的文件路径     *  $ve ...

  3. js计算总页数

    前端js取余是a%b 取除数parseInt(a / b) /** * 总页数@param(总条数,每页总条数) */ function pageTotal(rowCount, pageSize) { ...

  4. eclipse 安装合适的pydev插件

    http://www.cnblogs.com/yanduanduan/p/7261500.html

  5. redis 作为 mysql的缓存

    使用redis做为MySQL的缓存   介绍 在实际项目中,MySQL数据库服务器有时会位于另外一台主机,需要通过网络来访问数据库:即使应用程序与MySQL数据库在同一个主机中,访问MySQL也涉及到 ...

  6. HTML5 学习08——Input 类型、表单元素及属性

    注意:并不是所有的主流浏览器都支持新的input类型,不过您已经可以在所有主流的浏览器中使用它们了.即使不被支持,仍然可以显示为常规的文本域. (1)Input 类型: color color 类型: ...

  7. HTML 回顾整理

    <html>标签:定义HTML文档 <body>标签:定义文档主体 <h1> - <h6> 标签:定义HTML标题 <hr> 标签:创建水平 ...

  8. SQL批量更新数据

    SQL批量更新数据 step1:导入Excel数据, 具体见百度.注意点:一列中含有float型数据和文本数据的时候,导入要将Excel中的表格属性改成文本,或在数字项目前加个单引号.   step2 ...

  9. IE环境表单提交不跳转页面

    <head> <base target="_self"></base> </head>

  10. Centos7离线安装redis

    1.1 下载.上传.解压redis4.0.11 下载地址:http://download.redis.io/releases/redis-4.0.11.tar.gz下载后上传到服务器上,并解压:备注: ...