測試一:使用member function建立action會產生gc,無論該函數是否訪問外部變量:html
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;若是不訪問外部變量,則只產生一次gcthis
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 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 = 100; actMember = () => { Debug.Log(iValue); }; } // gc 136B private void AnoymousFunctionWithLocalArg3() { int iValue = 1; int iValue2 = 2; actMember = () => { Debug.Log(iValue); Debug.Log(iValue2); }; } }
同時還能夠發現,匿名函數引用的外部變量的個數會影響gc的值,爲何呢?來分析一波:spa
能夠看到訪問外部變量的匿名函數,會致使
臨時對象的建立,這樣會致使gc,那位爲何每一個臨時變量的gc值不同呢,咱們來看一下這些臨時class的定義:
能夠看匿名函數所訪問的外部變量都會在臨時類裏面建立一個拷貝,這樣每一個類對象的大小就不同了。3d
附上類型定義的完整代碼,來龍去脈一目瞭然:code
public class TestAnonymousFunctionGC : MonoBehaviour { // Fields private Action actMember; private int iMember; // Methods public 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 { // Fields public static readonly TestAnonymousFunctionGC.<>c <>9; public static Action <>9__4_0; // Methods static <>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 { // 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.htmlhtm
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(); }