简述
- 当用 new创建了对象,而后面的流程中这个对象没有被重复使用,意味着这个对象在语句执行完后就变成了垃圾,C#中的GC就是在某些时候集中去清理这些垃圾的,对于大型项目来说,这会造成比较大的开销,影响性能
- 解决的办法 就是在最开始就 new 一个对象,然后后面的流程有需要就重复使用这个对象就好,不要每次使用的时候都要 new 一个来导致 GC
- GC是处理 堆 上的内存的,原理是如果 堆 上的内存差不多被丢满了的话,GC就会出手回收没有被重复利用的内存,所以要避免多次在 堆 上放内存
代码手动回收
System.GC.Collect()
如何避免常见的GC
-
在Update中使用射线检测时,会疯狂创建数组,会产生GC
void Update() { Physics.RaycastAll(new Ray()); }
可以使用
Physics.RaycastNonAlloc
避免,下面只创建了一次数组private RaycastHit[] hits = new RaycastHit[10]; void Update() { Physics.RaycastNonAlloc(new Ray(), hits); }
-
协程
-
当使用
yield return
的时候也会产生一个新的对象IEnumerator Wait() { // 协程返回会创建一个引用类型数据 yield return new WaitForSeconds(5f); }
可以用 多个协程使用同一个对象来解决问题
private WaitForSeconds delay = new WaitForSeconds(5f); IEnumerator Wait() { // 协程返回会创建一个引用类型数据 yield return delay; }
可以写一个具体的 YieldHelper 做为一个工具类,来具体处理协程提前应该创建好的变量,进而消除协程的GC
// yield 的意思是产出 IEnumerator WaitToDo(float setTime) { // 这里的堵塞逻辑其实是 yield return YieldHelper.WaitForSeconds(setTime); // do something } public static class YieldHelper { public static IEnumerator WaitForSeconds(float totalTime) { float time = 0; while (time < totalTime) { time += Time.deltaTime; yield return null; // 等待一帧 } } }
-
-
实例化对象
- 实例化对象产生大量垃圾
Instantiate(new GameObject());
- 解决手段是 使用对象池技术来解决这个问题
- 实例化对象产生大量垃圾
-
Debug.Log()
究极内鬼-
只需要调用一次就可以产生 1.4kb 的垃圾…
-
解决方法是 可以在最终整合版本的时候删掉,也可以在发布游戏前,关闭日志消息功能
Debug.unityLogger.logEnabled = false;
-
最后,其实在游戏中产生垃圾并没有什么问题,主要问题是别高频率的产生垃圾,否则在大项目里的卡顿是非常频繁的