【Unity】减少GC回收

本文介绍了几种减少垃圾收集(GC)频率的方法,包括使用StringBuilder替代字符串连接操作、使用for循环代替foreach、避免直接访问GameObject的tag属性、使用对象池、减少LINQ的使用等。这些方法有助于提高程序运行效率。

两种情况GC会被触发:

  1. 堆的内存不足时自动调用GC。
  2. 手动的调用GC。


减少GC回收要注意一下问题:SFT池GCNL


  1. 字符串连接的处理。使用StringBuilder或String.Format来代替而不是用”+”来进行连接。因为将两个字符串连接的过程,其实是生成一个新的字符串的过程。而之前的旧的字符串就成为了垃圾。而作为引用类型的字符串,其空间是在堆上分配的,被弃置的旧的字符串的空间会被GC当做垃圾回收。
  2. 尽量不要使用foreach,而是使用for。foreach会涉及到迭代器enumerator的使用,而据传说每一次循环所产生的迭代器会带来24 Bytes的垃圾。那么循环10次就是240Bytes。
  3. 不要直接访问gameobject的tag属性。比如if (go.tag == “human”)最好换成if (go.CompareTag (“human”))。因为访问物体的tag属性会在堆上额外的分配空间。如果在循环中这么处理,留下的垃圾更多。
  4. 使用“池”,以实现空间的重复利用。
  5. 尽可能避免使用LINQ。部分功能无法在某些平台上使用,会分配大量GC Alloc。而且我很讨厌LINQ的一点就是它有可能在某些情况下无法很好的进行AOT编译。比如“OrderBy”会生成内部的泛型类“OrderedEnumerable”。这在AOT编译时是无法进行的,因为它只是在OrderBy的方法中才使用。所以如果你使用了OrderBy,那么在IOS平台上也许会报错。
  6. 缓存组件:

           1.每次GetComponent均会分配一定的GC Allow.

           2.每次Object.name都会分配39B的堆内存.


  7. 协程Coroutine,开启一个协程,至少分配373的内存。
  8. 尽量减少New的使用。
  9. Lambda表达式,使用不当会产生内存泄漏。
  10. 用Struct代替Class。

参考文章:深入浅出聊优化:从Draw Calls到GC

   2014Unity亚洲开发者大会会议简录之技术篇

### Unity3D 中资源管理和垃圾回收最佳实践 #### 优化垃圾回收频率和影响 为了减少因垃圾回收而导致的游戏性能下降,开发者应关注如何降低对象创建的数量以及控制不可达对象的生命周期。Unity 使用垃圾回收机制来处理不再使用的托管对象,当垃圾回收过于频繁时会影响应用流畅度[^1]。 对于动态分配的对象,建议尽可能复用已存在的实例而不是不断新建销毁它们;另外还可以通过设置合适的代数阈值调整GC行为模式以适应具体项目需求。例如: ```csharp // 预先缓存可重复利用的对象池 private static List<MyObject> objectPool = new(); public MyObject GetPooledObject() { if (objectPool.Count > 0) { var obj = objectPool[objectPool.Count - 1]; objectPool.RemoveAt(objectPool.Count - 1); return obj; } else { // 如果没有可用对象,则创建新对象 return new MyObject(); } } public void ReturnToPool(MyObject obj) { objectPool.Add(obj); } ``` #### 合理加载与卸载Assets 针对大体积资产文件如纹理贴图、音频片段等,应该采用按需异步加载的方式,并及时释放不再需要的数据。官方文档提供了详细的资产管理指南,强调了合理规划AssetBundles的重要性[^2]。 特别是自Unity 5.3.3版本起引入的新方法`AssetBundle.LoadFromFileAsync()`可以有效提高加载效率并减轻主线程压力[^3]。下面是一个简单的例子展示如何安全地加载和清理AB包中的内容: ```csharp IEnumerator LoadAndUnloadAssetBundle(string path){ using(var request = AssetBundle.LoadFromFileAsync(path)){ yield return request; if(!request.isError){ var bundle = request.assetBundle; // 加载所需资源... GameObject prefab = bundle.LoadAsset<GameObject>("MyPrefab"); // 卸载未被引用的资源 Resources.UnloadUnusedAssets(); bundle.Unload(false); // false表示只卸载此bundle本身而不影响其内部已被实例化的assets // 清除所有等待回收内存区域 GC.Collect(); } } } ``` #### 利用Memory Profiler工具监控内存状态 开发过程中应当充分利用内置的记忆分析器(Profiler),它可以帮助识别潜在的问题所在之处。Unity 对 C++ 层面进行了扩展,在每次申请堆空间时都会附加一个标签用于分类统计不同用途下的消耗情况[^4]。这使得定位特定类型的泄漏变得更加容易。 借助 Memory Snapshot 功能定期抓取快照对比前后差异,从而发现异常增长的趋势并采取相应措施加以修正。比如观察哪些地方存在过多的小型碎片化区块或是长时间驻留的大块连续区段。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值