测试一:使用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. BZOJ.1115.[POI2009]石子游戏Kam(阶梯博弈)

    BZOJ 洛谷 \(Description\) 有\(n\)堆石子.除了第一堆外,每堆石子个数都不少于前一堆的石子个数.两人轮流操作,每次可以从一堆石子中拿掉任意多的石子,但要保证操作后仍然满足初始时 ...

  2. BZOJ.4052.[Cerc2013]Magical GCD(思路)

    BZOJ \(Description\) 给定\(n\)个数的序列\(a_i\).求所有连续子序列中,序列长度 × 该序列中所有数的gcd 的最大值. \(n\leq10^5,\ a_i\leq10^ ...

  3. 英语口语练习系列-C23-运动

    基本词汇 1. build [bɪld] v. 建立.建造 built (过去式) be built (被动语态形式)被建成 The bridge was built in 1880. 这座桥1880 ...

  4. 摆脱CSS浏览器私有属性-moz, -ms, -webkit

    为了兼容各个浏览器之间的私有属性,前端开发人员在写css的时候需要给一些css属性添加多个私有前缀,非常麻烦.这里给大家分享一个简单的方法可以让你以后无需手动给CSS添加私有属性. -moz代表fir ...

  5. 数组中&a与&a[0]的区别 转载自http://blog.csdn.net/FX677588/article/details/74857473

    在探讨这个问题之前,我们首先来看一道笔试题,如下: [摘自牛客网]下列代码的结果是:(正确答案是 C) main() { int a[5]={1,2,3,4,5}; int *ptr=(int *)( ...

  6. TypeScript语法学习--基本类型

    查看官方文档手册:链接:https://www.tslang.cn/docs/home.html (一)Boolean 最基本的数据类型就是简单的true/false值 The most basic ...

  7. C C++ 数字后面加 LL是什么意思

    long long类型,在赋初值的时候,如果大于2的31次方-1,那么后面需要加上LL

  8. c c++ 函数不要返回局部变量的指针

    结论:普通的变量(非new的变量)都是系统自动分配的,在栈空间(连续分配),无需程序员操作,速度快,但是...空间有限,不适合大量数据,大量的话就需要自己new new出来的变量是处于大容量的堆空间, ...

  9. C_求质数

    质数:质数(prime number)又称素数,有无限个.质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数,这样的数称为质数. 题设:输入一个大于1的自然数,求出从2到该数之间所有的质数 ...

  10. JS_高程6.面向对象的程序设计(2)创建对象_1

    一.创建对象的常见方法 (1)Object构造函数创建单个对象,早期的JavaScript开发人员经常使用该模式创建新对象. var person=new Object(); person.name= ...