匿名函数gc分析
?測試一:使用member function創(chuàng)建action會產(chǎn)生gc,不管該函數(shù)是否訪問外部變量:
private System.Action memberAct = null;// gc 112Bprivate void ActionWithMethod(){memberAct = new System.Action(LocalMethod);}// gc 112B, if LocalMethod() is static, then no gcprivate void ActionWithMethod2(){memberAct = LocalMethod;}// no gcprivate void ActionWithMethod3(){System.Action act = memberAct;}private void LocalMethod(){foreach (var item in lst)Debug.Log(item);}ActionWithMethod和ActionWithMethod2是等效的,gc值如下所示:
IL代碼也一摸一樣:
所以將一個member function復制給一個action會產(chǎn)生gc,解決的辦法就是ActionWithMethod3,也就是用一個actin member緩存起來,然后將緩存的action member復制給新建的action,這樣只會產(chǎn)生一次gc:
如果將LocalMethod設(shè)置為static函數(shù),則ActionWithMethod2也不會產(chǎn)生gc: private static void LocalMethod(){}
?
測試二:使用匿名函數(shù),如果訪問了外部變量,也會產(chǎn)生gc;如果不訪問外部變量,則只產(chǎn)生一次gc
using System.Collections; using System.Collections.Generic; using UnityEngine; public class TestAnonymousFunctionGC : MonoBehaviour {private System.Action actMember = null;private int iMember = 1;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 gcprivate void AnoymousFunctionWithoutArg(){actMember = () => { };}// gc 112Bprivate void AnoymousFunctionWithMemberArg(){actMember = () =>{Debug.Log(iMember);};}// gc 129Bprivate void AnoymousFunctionWithLocalArg1(){bool bValue = true;actMember = () =>{Debug.Log(bValue);};}// gc 132Bprivate void AnoymousFunctionWithLocalArg2(){int iValue = 100;actMember = () =>{Debug.Log(iValue);};}// gc 136Bprivate void AnoymousFunctionWithLocalArg3(){int iValue = 1;int iValue2 = 2;actMember = () =>{Debug.Log(iValue);Debug.Log(iValue2);};} }
同時還可以發(fā)現(xiàn),匿名函數(shù)引用的外部變量的個數(shù)會影響gc的值,為什么呢?來分析一波:
可以看到訪問外部變量的匿名函數(shù),會導致臨時對象的創(chuàng)建,這樣會導致gc,那位為什么每個臨時變量的gc值不一樣呢,我們來看一下這些臨時class的定義:
可以看匿名函數(shù)所訪問的外部變量都會在臨時類里面創(chuàng)建一個拷貝,這樣每個類對象的大小就不一樣了。
附上類型定義的完整代碼,前因后果一目了然:
public class TestAnonymousFunctionGC : MonoBehaviour {// Fieldsprivate Action actMember;private int iMember;// Methodspublic TestAnonymousFunctionGC(){this.actMember = null;this.iMember = 1;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 = 1;this.actMember = new Action(class_.<AnoymousFunctionWithLocalArg1>b__0);return;}private void AnoymousFunctionWithLocalArg2(){<>c__DisplayClass7_0 class_;class_ = new <>c__DisplayClass7_0();class_.iValue = 100;this.actMember = new Action(class_.<AnoymousFunctionWithLocalArg2>b__0);return;}private void AnoymousFunctionWithLocalArg3(){<>c__DisplayClass8_0 class_;class_ = new <>c__DisplayClass8_0();class_.iValue = 1;class_.iValue2 = 2;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{// Fieldspublic static readonly TestAnonymousFunctionGC.<>c <>9;public static Action <>9__4_0;// Methodsstatic <>c(){<>9 = new TestAnonymousFunctionGC.<>c();return;}public <>c(){base..ctor();return;}internal void <AnoymousFunctionWithoutArg>b__4_0(){return;}}[CompilerGenerated]private sealed class <>c__DisplayClass6_0{// Fieldspublic bool bValue;// Methodspublic <>c__DisplayClass6_0(){base..ctor();return;}internal void <AnoymousFunctionWithLocalArg1>b__0(){Debug.Log((bool) this.bValue);return;}}[CompilerGenerated]private sealed class <>c__DisplayClass7_0{// Fieldspublic int iValue;// Methodspublic <>c__DisplayClass7_0(){base..ctor();return;}internal void <AnoymousFunctionWithLocalArg2>b__0(){Debug.Log((int) this.iValue);return;}}[CompilerGenerated]private sealed class <>c__DisplayClass8_0{// Fieldspublic int iValue;public int iValue2;// Methodspublic <>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函數(shù)會有g(shù)c:
// 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();}?
?
總結(jié)
- 上一篇: Scala学习(十二)高阶函数
- 下一篇: 瑞典公司推出“安全气囊牛仔裤”,专为摩托