• 匿名函数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();
            }

     

  • 相关阅读:
    N25_复杂链表的复制
    N24_二叉树中和为某一路径
    N23_判断是否为二叉搜索树的后序遍历序列
    N22_从上到下打印二叉树
    win7桌面小工具已停止工作解决办法
    C3P0数据库连接池使用
    js中的页面跳转
    怎么用js代码禁止浏览器的前进与后退?
    怎么在 Dos 下运行 PHP 和 MySQL 命令
    80端口被system 占用解决方法
  • 原文地址:https://www.cnblogs.com/sifenkesi/p/9762183.html
Copyright © 2020-2023  润新知