GC就是Grabage Collector,当没有任何栈内存所指向的堆内存空间,所有的垃圾将被GC不定期进行回收并且释放无用内存空间,使这些内存可以再次使用,但是如果垃圾过多将影响到GC的处理性能,从而降低整体的程序性能,在实际开发之中,对于垃圾的产生越少越好
对应的方法是GC.Collect,其功能就是强制对所有垃圾进行回收
Unity是自动内存管理,Unity中可以访问两个内存池:栈内存和堆内存,栈用于短期存储的小数据,堆用于较长时间存储的较大的数据块。当创建变量的时候,Unity会从栈或堆中请求一个内存块,只要变量值作用域内(仍可被代码访问),分配给它的内存就会保留。当变量不在作用域范围内了,这块内存就不再需要了,可以被创建它的那个内存池回收。只要变量的引用超出了作用域,栈内存就会被重新分配,而堆的内存不同,堆内存不会重新分配即使变量的引用超出了作用域,垃圾回收器会标识没有使用的堆内存,之后定期清理堆内存
——Unity检测是否有足够的闲置内存单元用来存储数据,如果有,则分配对应大小的内存单元
——如果没有足够的存储单元,Unity会触发垃圾回收(GC)来释放不再被使用的堆内存。这步操作是一步缓慢的操作,如果GC后有足够大小的内存单元,则进行内存分配
——如果GC后并没有足够的内存单元,Unity会扩展堆内存的大小,这步操作也会很缓慢,然后分配对应大小的内存单元给变量
GC是一个极其消耗性能的工作,每次都需要遍历整个堆内存,堆内存上的变量或者引用越多其运行的操作会更多,耗费的时间就越长
登录后复制
class Person{ String name; int age; }public class JavaDemo{ public static void main(String args[]) { Person per1 = new Person(); Person per2 = new Person(); per1.name = "liu"; per1.age = 11; per2.name = "yin"; per2.age = 12; per2 = per1; per2.age = 100; }}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.
例如上面这段代码,当实例化per1和per2时会分配内存,当将per1的引用给per2时,per2分配的内存就变成了内存垃圾,这时候这段内存就会被被标记为垃圾之后在某个时候自动被释放掉
——堆分配时堆上的可用内存不足时触发GC
——GC会不时的自动运行(频率因平台而异)
——手动强制调用GC.Collect
——减少频繁分配内存
避免在Update、LateUpdate等每帧调用的函数中频繁分配内存
登录后复制
void Update() { List<int> list = new List<int>(); Fun(list);}1.2.3.4.5.
上面这种写法,每次new都会分配一次内存
登录后复制
private List<int> list = new List<int>(); void Update() { list.Clear(); Fun(list);}1.2.3.4.5.6.
上面这种写法只有在容器被创建或者扩容时才会有堆分配,从而减少了垃圾内存的产生
——运用对象池
在运行时大量对象的创建和销毁依然会引起GC问题,用对象池技术可以让对象复用而不是重复的创建和销毁
——字符串
在C#中,String是引用类型,它的值是不可变的,一旦被初始化后就不能改变其内容,频繁的修改字符串建议使用StringBuilder
C#中的String和StringBuilder
——Unity函数的调用
例如GameObject.name或GameObject.tag会返回一个新的字符串,意味着频繁调用会产生内存垃圾,可以使用CompareTag代替
登录后复制
private string playerTag = "Player"; void OnTriggerEnter(Collider other) { bool isPlayer = other.gameObject.tag == playerTag;}1.2.3.4.5.
上面这种写法每次访问GameObject.tag会产生内存垃圾
登录后复制
private string playerTag = "Player"; void OnTriggerEnter(Collider other) { bool isPlayer = other.gameObject.CompareTag(playerTag);}1.2.3.4.5.
上面这种写法不会产生内存垃圾
——装箱
值类型转换为引用类型的过程称为装箱,装箱会产生GC
——协程
避免yield return 0,因为会产生GC,因为int类型的0被装箱,而使用yield return null替代则不会产生装箱操作
还比如在协程中避免多次new同一个WaitForSeconds对象
登录后复制
while (!isComplete) { yield return new WaitForSeconds(1f);}1.2.3.4.
上面这种写法每次循环都会分配一次新内存
登录后复制
WaitForSeconds delay = new WaitForSeconds(1f); while (!isComplete) { yield return delay;}1.2.3.4.5.
上面这种写法只会分配一次内存
——Linq表达式
LINQ和正则表达式由于在后台会有装箱操作而产生垃圾,在有性能要求的时候最好不使用
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删