• Unity GC优化原理及实践-1堆栈


    1.示例(堆栈上的内存分配):

    public class Point
    {
        public float pointX { get; set; }
        public float pointY { get; set; }
    }
    
    class StartProgram : MonoBehaviour
    {
        void Start()
        {
            float pointX = 100.1f;
            InitialPoint(pointX);
        }
    
        private void InitPoint(float pointX)
        {
            Point point = new Point();
            point.PointX = pointX;
        }
    }

    首先将Start()方法指令压入栈底,然后压入局部变量pointX。接着将InitPoint()方法压入栈底,形参pointX压入栈底,在堆上实例化Point对象(包括其成员变量PointX和PointY),并在栈上创建point变量指向堆上的Point对象,最后给成员变量PointX赋值

    (1)创建引用类型时,会为其分配两个空间,一块空间分配在堆上,存储引用类型本身的数据,另一个块空间分配在栈上,存储对堆上数据的引用

    (2)创建值类型时, 会为其分配一个空间,这个空间分配在变量创建的地方

    如果值类型是在方法内部创建,则跟随方法入栈,分配到栈上存储。

    如果值类型是引用类型的成员变量,则跟随引用类型,存储在堆上。

    2.堆栈的特点

    (1)栈是一种先进后出的内存结构,只能在一端对数据进行操作,也就是栈顶端进行操作

    (2)方法的调用追踪

    (3)栈也是一种内存自我管理的结构,压栈自动分配内存,出栈自动清空所占内存

    (4)栈中的内存不能动态请求,只能为大小确定的数据分配内存,灵活性不高,但是栈的执行效率很高。

    (5)栈的可用空间并不大,所以我们在操作分配到栈上的数据时要注意数据的大小带来的影响。

    (1)堆在C#中用于存储实实例对象,能存储大量数据,而且堆能够动态分配存储空间。

    (2)相比栈只能在一端操作,堆中的数据可以随意存取。容易产生内存碎片

    (3)堆的结构使得堆的执行效率不如栈高,不能自动回收使用过的对象。Unity和lua使用的GC器是标记-清除。

    3.数据传递的三种类型

    (1)按值传递

    public struct PointStruct
    {
        public float pointX { get; set; }
        public float pointY { get; set; }
    }
    
    public class PointClass
    {
        public float pointX { get; set; }
        public float pointY { get; set; }
    }
    
    void Start()
    {
        PointStruct pointStruct1 = new PointStruct();
        PointClass pointClass1 = new PointClass();
        PointStruct pointStruct2 = pointStruct1;
        PointClass pointClass2 = pointClass1;
    }

    创建了一个结构体pointStruct1和一个类实例pointClass1, 结合上面的内存分配规则,对于pointSturct1,会在栈上分配内存存储其数据本身,对于pointClass1,会在堆上分配内存存储实例,且在栈上存储指向实例的引用

    (2) 参数传递

    void Start()
    {
        float pointX1 = 100.1f;
        Point point1 = new Point();
        point1.pointX = 200.1f;
        InitialPoint(pointX1, point1);
        Debug.Log(string.Format("pointX1:{0}", pointX1));
        Debug.Log (string.Format("point1.PointX:{0}", point1.PointX));
    }
    
    void InitPoint(float pointX2, Point point2)
    {
        pointX2 = 300.1f;
        point2.pointX = pointX2;
    }

    void InitPoint(float pointX2, Point point2)
    {
        pointX2 = 300.1f;
        point2.pointX = pointX2;
        point2 = null;
    }

    point2设置为null的含义,并不将堆上的实例变为null,而是设置栈上的引用为null

    (3) 按引用传递(Ref和Out关键字)

    void Start()
    {
        float pointX1 = 100.1f;
        Point point1 = new Point();
        point1.pointX = 200.1f;
        Point point2 = point1;
        InitPoint(ref pointX1, ref point1);
        Debug.LogWarning(string.Format("pointX1:{0}", pointX1));
        if (point1 != null)
            Debug.LogWarning(string.Format("point1.pointX:{0}", point1.pointX));
        else
            Debug.LogWarning(string.Format("point1 is null"));
    
        if (point2 != null)
            Debug.LogWarning(string.Format("point2.pointX:{0}", point2.pointX));
        else
            Debug.LogWarning(string.Format("point2 is null"));
    }
    
    void InitPoint(ref float pointX2, ref Point point3)
    {
        pointX2 = 300.1f;
        point3.pointX = pointX2;
        point3 = null;
    }

     

    避坑

     

  • 相关阅读:
    sqlserver2008导出表结构和数据
    使用adb命令对手机进行截屏保存到电脑
    android中控制多点同时触发时间
    使用Androi自带模拟器7.0版本无法安装apk解决
    Android library使用butterknife配置
    使用RadioGroup和fragment搭建项目框架填坑
    【转】BaseAdapter&DataSetObserver通知机制
    【转】读BaseAdapter的一点感悟
    使用Rxjava和Retrofit报错--01
    使用LeakCanary检测内存泄漏
  • 原文地址:https://www.cnblogs.com/DonYao/p/15254478.html
Copyright © 2020-2023  润新知