什么是GC
- 游戏运行的时候,数据主要存储在内存中,当游戏数据不再需要的时候,当前这部分内存就可以被回收,以便再次利用。内存垃圾指当前废弃数据所占用的内存,GC是指将废弃的内存进行回收,使其可以再次被使用的过程。
- 垃圾回收器只回收内存,不回收其他资源,如:数据库连接,文件句柄,网络端口,硬件设备等。
GC原理
- mark-and-compact算法,mark是指先确定所有可达对象,compact是指移动这些对象,使它们紧挨着存放。整个过程有点儿像磁盘碎片整理。
终结器 Finalizer
- GC 负责为对象实例调用终结器。不能在编译时确定终结器的执行时间,唯一确定的是终结器会在对象最后一次使用之后的某个时间点调用。
- 确定性终结见:[[CS-using#自动释放资源]]
- 终结器很可能永远不会被调用。
- 终结器在对象被 GC 判定为不可达的某个时间点执行,执行后再将其从终结队列中删除,使其可以再次使用。
- 终结器不负责回收内存。终结器负责释放文件句柄之类的资源。
1 2 3 4 5 6 7 8 9 10
public class FileStream { // 构造函数 public FileStream() {} // 声明终结器的语法和C++的析构器完全一致 ~FileStream() { // todo something } }
内存垃圾太多会导致的问题
- GC调用越频繁,耗费CPU越多。
- GC调用频繁,会导致内存命中率下降。
- 堆内存碎片会导致占用内存越来越大,GC操作更加频繁。
GC触发时机
- 如果申请堆内存,堆内存不够,就会触发GC操作来回收闲置的内存。
- 各个平台会定时自动触发GC。
主动触发一次GC
1
System.GC.Collect();
怎样减少GC
- 缓存对象,不要在 Update 中频繁GetComponent。
- 减少逻辑调用。每帧调用变成隔一秒调用等。
- 复用 List,缓存下来,使用 Clear 清空,而不是 new 一个新的。
- 使用对象池。
- 字符串使用要格外小心,text要赋值的字符串尽量做到最短,把变化的数值独立出来。
- 减少字符串的使用,如果字符串拼接操作比较多,使用 [[CS-StringBuilder]]。
- 正式版移除
Debug.Log()
,它不但分配字符串,还不间断的往文件写数据。 - 不要使用 LINQ。
- 使用公用的静态成员对象。
- 减少装箱和拆箱。