GC垃圾回收机制

托管堆:由Mono分配与管理。而托管的 意思是可以自动改变堆的大小,适应内存的需要,适合时机调用GC释放内存。


Unity内存管理机制

1、Unity存在2个内存管理区域,堆和堆栈,堆栈一般存储小和短暂的数据,堆存储大和时间长的数据
2、堆和堆栈之间差异:堆栈分配与回收较快。而堆在分配内时,先检查是否有内存,如果没有,将会进行GC,堆在GC后内存仍然不足时,将会申请内存,但是GC所释放的内存,将会留给Mono,而不会返还给操作系统。GC时,会暂停那些需要Mono内存分配的线程。其中在GC和内存的扩展时很慢
问题:对于Mono内存的申请机制不了解,就不知道为什么要先申请大内存的,然后再申请小内存
答:因为先申请小的内存,再去申请大的内存时候,空闲内存肯定是不够的,所以将会出发GC或者内存扩展


GC

1、值类型变量在堆栈内存上分配,其他类型变量在推内存上分配

函数结束,立即回收
void Func(){
    int a = 1;
}
函数结束,不会立即回收,需要等待GC
void Func(){
    List lists = new List();
}

2、相关的解决方法:

  • 常用的函数中 尽量不要去进行内存的分配,利用缓存代替,比如函数中分配数组,可以选择用在外部定义一个缓存数组
  • Unity的Update中分配内存会产生很大的内存垃圾,可以考虑设置定时或者判断减少产生内存分配函数的调用

常见的不必要的内存分配

1、字符串,字符串在C#是类,并且字符串在创建完后将不可被改变,一旦改变相当于创建了一个新的字符串对象,原来的将会废弃,可以直接采用StringBuilder拼接。并且Debug.Log会造成很大的内存垃圾


Debug.Log造成的内存垃圾

2、Unity某些函数会产生内存垃圾

  • 如果unity中函数返回数组,那么每次都会分配一个数组,如下的循环就是如此
void Func(){
    for(int i=0; i
  • 其中gameObject.name或者gameObject.tag, 都将返回字符串,这样会造成不必要的内存垃圾。其中gameObject.CompareTag()。可以有效的避免内存垃圾

装箱操作

1、装箱操作就是将值类型被用作引用类型之间的变换。比如我们向需要引用类型参数的函数传入值类型,这时将会触发装箱操作。
2、对于装箱操作,将会为值类型分配一个System.Object对象,这样就多了不必要的引用类型,从而造成不必要的内存消耗。


协程

1、如yield return 0将会触发装箱操作,利用yield return null代替
2、yield return new WaitForSeconds(1)每次将会创建一个新对象。所以我们可以提前缓存一个这样的对象,从而放置每次都new一个新对象。


其他情况

1、结构体Struct中如果包含引用类型变量,那么GC将会检查这个结构体。所以使用上需要注意
2、当一个对象内包含对另一个对象的引用,那么GC将不得不去检查

public class Person{
    private Person neighbor;
    xxx
}

重构后, 最后通过Id得到相应的结果
public class Person{
    private int neighborId;
    xxx
}

你可能感兴趣的:(GC垃圾回收机制)