增量垃圾收集 (GC) 将垃圾收集过程分散到多个帧中。这是 Unity 中的默认垃圾收集行为。
Unity 的垃圾收集器使用 Boehm–Demers–Weiser 垃圾收集器。默认情况下,Unity 以增量模式使用垃圾收集器,这表示垃圾收集器将其工作负载分解在多个帧上,而不是停止主 CPU 线程(可停止所有工作的垃圾收集),从而处理托管堆上的所有对象。这意味着 Unity 会缩短应用程序执行的中断时间,而不会在垃圾收集器处理托管堆上的对象时保持较长的中断时间。
增量模式不会整体加快垃圾收集的速度,但由于它将工作负载分解在多个帧上,所以与 GC 相关的性能尖峰会降低。这些中断因为在性能分析器 (Profiler) 窗口的帧时间图中显示为大尖峰,所以也称为 GC 尖峰。
如果禁用增量模式(菜单:编辑 (Edit) > 项目设置 (Project Settings) > 播放器 (Player) > 其他设置 (Other Settings) > 配置 (Configuration) > 使用增量垃圾收集 (Use Incremental GC)),垃圾收集器在执行收集过程中必须检查整个堆。由于垃圾收集器每次运行时都会停止主 CPU 线程,所以这被称为停止所有工作的垃圾收集。仅当处理完托管堆上的所有对象后,该线程才会恢复执行,这可能会导致 GC 尖峰影响应用程序的性能。垃圾收集器还是非压缩的,这意味着 Unity 不会重新分布内存中的任何对象来弥补对象之间的空隙。
重要提示:Web 平台不支持增量垃圾收集。
禁用增量垃圾收集后,Unity 停止运行程序代码以执行垃圾收集时,会出现 GC 尖峰。此延迟可能会持续数百毫秒,具体取决于垃圾收集器需要处理的分配数量以及运行应用程序的平台。
这对于实时应用程序(例如游戏)来说会产生问题,因为当垃圾收集器暂停应用程序执行时,应用程序很难保持平滑动画所需的一致帧率。
下面的性能分析器截屏说明了增量垃圾收集减少帧率问题的方式:
在顶部的性能分析会话中,增量垃圾收集启用。应用程序保持一致的 60fps 帧率,因为垃圾收集器将垃圾收集操作分解到若干帧中,并且使用每帧的一小段时间(位于黄色__ VSync__垂直同步 (VSync) 是一种显示设置,可限制游戏帧频,使其与显示器的刷新率相匹配,以防止图像撕裂。
See in Glossary 跟踪记录上方的深绿色条纹)。
在底部的性能分析会话中,增量垃圾收集禁用,因此出现了明显的 GC 尖峰。此尖峰会中断原本平滑的 60fps 帧率,并将发生垃圾收集的帧推过保持 60fps 帧率所需的 16 毫秒限制。
如果应用程序使用 VSync 或 Application.targetFrameRate,Unity 会根据剩余的可用帧时间调整分配给垃圾收集的时间。这样,Unity 可以及时运行垃圾收集(否则需要等待),从而以最低的性能影响执行垃圾收集。
注意:如果将 VSync 计数 (VSync Count) 设置为不同步 (Don’t Sync) 之外的选项(位于项目的质量 (Quality) 设置中或使用 Application.VSync 属性),或者启用了 Application.targetFrameRate 属性,则 Unity 会自动使用给定帧末尾剩余的空闲时间来运行增量垃圾收集。
要对增量垃圾收集行为进行更精确的控制,可以使用 Scripting.GarbageCollector 类。例如,如果不想使用 VSync 或目标帧率,则可以自行计算帧结束之前的可用时间,并将该时间提供给垃圾收集器使用。
增量垃圾收集可能会导致应用程序出现问题,因为当垃圾收集器在此模式下拆分工作时,也会拆分标记阶段。标记阶段是垃圾收集器扫描所有托管对象以确定仍在使用的对象以及可以清理的对象的阶段。
当对象之间的大部分引用在工作片段之间不变时,拆分标记阶段没有问题。但是,当对象引用发生变化时,垃圾收集器必须在下一次迭代中再次扫描这些对象。这意味着过多的更改可能会使增量垃圾收集器负担过重,并造成标记阶段因为任务过多而永远无法完成的情况。如果发生这种情况,垃圾收集器会回退到执行完整的非增量收集。
Unity 使用增量垃圾收集时,会生成额外的代码(称为写屏障),以便在引用发生更改时通知垃圾收集器,从而确定是否需要重新扫描对象。更改引用时,这会增加一些开销,可能会对托管代码产生性能影响。
要禁用增量垃圾收集,请打开运行设置 (Player Settings) 窗口(编辑 (Edit) > 项目设置 (Project Settings) > 播放器 (Player) > 配置 (Configuration))并禁用使用增量垃圾收集 (Use Incremental GC)。增量垃圾收集可对大多数 Unity 项目产生优势,特别是当这些项目受到垃圾收集尖峰的影响时,但应始终使用性能分析器来验证应用程序是否按预期运行。