匿名函数gc分析

 测试一:使用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 = 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的值,为什么呢?来分析一波:

  

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

  

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

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

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.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();
        }

 

 

posted @ 2018-10-09 19:02  斯芬克斯  阅读(1239)  评论(0编辑  收藏  举报