尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

【Unity小白学习日记3】吃透GC——C# 的垃圾回收器

【Unity小白学习日记3】吃透GC——C# 的垃圾回收器 前言✨1、GC 垃圾回收是什么2、GC的工作流程3、什么会产生 GC重点Unity 考点4、Unity 中减少 GC 的手段5、GC 触发时机是什么6、【补充知识内存泄漏】常考问题Q物体 Destroy 了Mono 脚本一定被 GC 回收吗了解Q协程为什么会造成内存泄漏了解首先先明确GC必须要学习的几个知识点1、GC 垃圾回收是什么2、GC的工作流程3、什么情况会产生 GC4、Unity 中减少 GC 的手段5、GC 触发时机是什么6、【补充知识内存泄漏】接下来我将一个一个来讲讲我的理解1、GC 垃圾回收是什么GC 全称 Garbage Collector垃圾回收器。C# 是托管语言不需要开发者手动释放堆内存GC 自动扫描堆回收没有任何引用指向的对象释放堆内存。栈内存不受 GC 管理函数执行完自动释放。2、GC的工作流程工作流程标记阶段从根对象出发扫描所有能访问到、有引用的堆对象标记为存活。根对象包括静态变量、Mono 脚本、局部变量引用。清除阶段把没有标记、没有引用的对象判定为垃圾回收内存。压缩整理阶段压缩的时候会 STW暂停主线程这就是 Unity 卡顿的来源。STWStop‑The‑World所有用户逻辑暂停GC 工作的时候游戏会卡帧。3、什么会产生 GC重点Unity 考点new 引用类型对象 class、数组在堆分配内存。装箱拆箱值类型转 object堆上生成对象。字符串频繁拼接string 每次 生成新字符串。闭包 lambda捕获局部变量编译器生成隐藏类堆分配。foreach 旧版本迭代器、协程会生成迭代器对象。集合扩容List/Dictionary 容量不足内部 new 新数组。4、Unity 中减少 GC 的手段尽量减少 Update 里面 new 引用对象不要每帧 new。优先泛型集合ListT避免非泛型集合带来装箱。大量字符串拼接用StringBuilder。对象池复用物体、组件减少频繁 Instantiate/Destroy减少 new。集合预先设置 Capacity避免运行时扩容。少在循环、Update 写 lambda 闭包捕获局部变量。及时置空引用解除静态、单例对废弃对象的持有。可以手动调用GC.Collect()强制回收但不建议频繁调用会带来 STW 卡顿一般只适合场景切换的时候调用一次。5、GC 触发时机是什么GC 触发时机有三种第一new 新对象的时候托管堆剩余内存不够分配就自动触发回收第二代码手动调用 GC.Collect 强制回收游戏业务尽量不要手动调用第三IL2CPP/Mono 内部达到内存阈值自动触发不同平台阈值会不一样6、【补充知识内存泄漏】内存泄漏就是程序中已经不再使用的对象还被其他地方持有引用GC 无法对它进行回收这部分内存得不到释放。随着运行时间变长内存持续上涨会出现卡顿严重会造成内存溢出、闪退。Unity 里面最常见容易出现内存泄漏的几个原因第一事件订阅忘记移除监听。【比如说弹窗 UI 在 OnEnable 订阅金币变化事件关闭弹窗直接 Destroy 物体没有在 OnDisable 移除监听。物体销毁但事件中心字典仍然保存委托不仅会后续广播时报空引用Mono 对象也无法 GC 回收。】第二静态变量或者单例持有已经销毁的 Mono 对象。【比如单例管理器用静态变量保存玩家角色场景切换角色被销毁但静态变量没有置空产生伪 null对象得不到释放Mono 单例 OnDestroy 忘记清空 Instance 也属于这种情况。】第三协程没有停止。【如果协程是别的物体启动的目标物体被 Destroy 之后协程不会自动停止协程迭代器会持有销毁物体的引用造成泄漏注意物体自身启动的协程物体销毁会自动停止。】第四List、Dictionary 这类集合持续添加数据没有做清理。【例如战斗伤害飘字不断加入 List战斗结束只 Destroy UI 物体没有 Clear 集合集合一直持有对象引用内存持续累积上涨。 】开发规范OnEnable 订阅事件OnDisable 移除物体销毁时停止协程不要用静态变量缓存临时游戏物体Profiler 的 Memory 面板可以用来排查内存泄漏。常考问题Q物体 Destroy 了Mono 脚本一定被 GC 回收吗了解话术不一定。如果还有静态变量、事件委托、未停止的协程持有这个对象引用C# 对象不会被 GC 回收会出现伪 null。引擎层物体销毁C# 对象还留在内存就是内存泄漏。Q协程为什么会造成内存泄漏了解话术物体被 Destroy如果没有 StopCoroutine协程还会继续执行。协程的 IEnumerator 会持有 Mono 对象造成对象无法 GC 回收引发内存泄漏。物体销毁会自动停止该物体上所有协程但如果协程是其他对象启动的就不会自动停止。拓展知识托管内存和非托管内存先简单讲讲后续我会出详细的介绍托管内存由 .NET GC 管理非托管内存或非托管资源不由 GC 直接管理需要开发者显式释放。重点注意GC 负责回收托管对象的内存但不等于所有资源都自动释放。涉及文件、网络、数据库、Unity Native 资源时要实现或调用 IDisposable.Dispose() 优先用 using 必要时用 SafeHandle 管理非托管句柄。✨小何同学那些默默啃下的知识点终会变成面试里从容回答的底气。✨
返回列表