匿名函數gc分析

 測試一:使用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();
        }

 

相關文章
相關標籤/搜索