Version: 6000.3
语言: 中文
垃圾回收器概述
配置垃圾回收

垃圾回收模式

Unity 的垃圾回收器具有以下模式:

  • 增量垃圾回收:默认启用。此模式将垃圾回收过程分散到多个帧上。
  • 非增量垃圾回收模式:如果禁用增量 GC 播放器设置(“项目设置”>“播放器>配置”),垃圾回收器将停止运行应用程序来检查和处理堆上的对象。此模式也称为停止世界垃圾回收。
  • 手动垃圾回收:使用GarbageCollector.GCModeAPI 来完全控制 Unity 何时运行垃圾回收器。

有关如何使用每种垃圾回收模式的信息,请参阅配置垃圾回收

增量垃圾回收

增量垃圾回收将垃圾回收过程分散到多个帧上。这是 Unity 中的默认垃圾回收行为。

Unity 的垃圾回收器使用 Boehm-Demers-Weiser 垃圾回收器。默认情况下,Unity 在增量模式下使用它,这意味着垃圾收集器将其工作负载拆分到多个帧上,并缩短应用程序执行的中断时间。

非增量模式下,Unity 会在一次长时间中断中停止主 CPU 线程(停止世界垃圾回收),以处理托管堆上的所有对象。

增量模式不会加快垃圾回收速度,但由于它将工作负载分布在多个帧上,因此与垃圾回收相关的性能峰值会降低。这些中断称为 GC 峰值,因为它们在 Profiler 窗口的帧时间图中显示为大峰值。

重要:Web 平台不支持增量垃圾回收。有关更多信息,请参阅 Web 垃圾回收中的内存注意事项

增量垃圾回收示例

以下屏幕截图来自分析器帮助您优化游戏的窗口。它显示了在游戏的各个领域花费了多少时间。例如,它可以报告渲染、动画制作或游戏逻辑所花费的时间百分比。更多信息
请参阅术语表
说明增量垃圾回收如何减少帧速率问题:

启用增量 GC 的分析会话
启用增量 GC 的分析会话
禁用增量 GC 的分析会话
禁用增量 GC 的分析会话

在顶部分析会话中,启用了增量 GC 设置。应用程序具有一致的 60fps查看第一人称射击游戏,每秒帧数。
请参阅术语表
帧速率,因为垃圾回收器将垃圾回收作分布在多个帧上。垃圾回收器使用每帧的小时间片,由黄色 VSync 跟踪上方的深绿色条纹指示。

底部分析会话禁用了增量 GC 设置,并且可以看到 GC 峰值。GC 峰值会中断一致的 60 fps 帧速率,并将发生垃圾收集的帧推到保持 60 fps 所需的 16 毫秒限制以上。

如果您的应用程序使用VSync垂直同步 (VSync) 是一种显示设置,用于限制游戏的帧速率以匹配显示器的刷新率,以防止图像撕裂。
请参阅术语表
Application.targetFrameRate,Unity 会根据剩余的可用帧时间调整分配给垃圾回收的时间。这样,Unity 就可以在等待的时间内运行垃圾回收器,并且可以以最小的性能影响进行垃圾回收。

注意: 如果你将 VSync 计数(VSync Count) 设置为 不同步(Don't Sync) 以外的任何值(在项目的 质量(Quality) 设置中或使用Application.VSync属性),或者您启用Application.targetFrameRate属性,Unity 会自动使用给定帧结束时剩余的任何空闲时间进行增量垃圾回收。

要更精确地控制增量垃圾回收行为,您可以使用Scripting.GarbageCollector类。 例如,如果不想使用 VSync 或目标帧速率,则可以计算帧结束之前的可用时间量,并将该时间提供给垃圾回收器。

有关更多信息,请参阅配置垃圾回收

非增量垃圾回收模式

增量垃圾回收可能对应用程序来说是有问题的,因为当垃圾回收器在此模式下划分其工作时,它也会划分标记阶段。标记阶段是垃圾回收器扫描所有托管对象以确定哪些对象仍在使用以及可以清理哪些对象的阶段。

当对象之间的大多数引用在工作切片之间没有变化时,划分标记阶段效果很好。但是,当对象引用发生更改时,垃圾回收器必须在下一次迭代中再次扫描这些对象。这意味着过多的更改可能会使增量垃圾回收器不堪重负,并造成标记阶段永远不会完成的情况,因为它总是有更多的工作要做。如果发生这种情况,垃圾回收器将回退到执行完整的非增量回收。

当 Unity 使用增量垃圾回收时,它会生成额外的代码(称为写屏障),以便在引用发生更改时需要扫描对象时通知垃圾回收器。这会在更改引用时增加一些开销,这会影响托管代码的性能。

因此,在某些情况下,您可能希望禁用增量垃圾回收以提高应用程序的性能。禁用增量模式时,垃圾回收器在执行收集传递时必须检查整个堆。

这被称为停止世界垃圾回收,因为每当垃圾回收器运行时,它都会停止主 CPU 线程。只有在处理完托管堆上的所有对象后,它才会恢复执行,这可能会导致 GC 峰值影响应用程序的性能。此延迟可能会持续数百毫秒,具体取决于垃圾回收器需要处理的分配数量以及应用程序运行的平台。

垃圾收集器也是非压缩的,这意味着 Unity 不会重新分配内存中的任何对象来缩小对象之间的间隙。

对于游戏等实时应用程序来说,非增量垃圾回收存在问题,因为当垃圾回收器挂起应用程序的执行时,应用程序很难维持平滑动画所需的一致帧速率。

要禁用增量垃圾回收,请参阅配置垃圾回收

手动垃圾回收

您可以使用GarbageCollector.GCMode用于在运行时禁用垃圾回收的 API。这可以防止 CPU 峰值,但应用程序的内存使用量永远不会减少,因为垃圾回收器不会收集不再具有任何引用的对象。

禁用垃圾回收器需要仔细的内存管理,否则托管堆会不断扩展,直到应用程序内存不足,并且作系统将其关闭。

最佳做法是在应用程序的简短、性能关键部分禁用垃圾回收,此时你能够计算和控制要分配的内存量。性能关键部分结束后,重新启用垃圾回收器。分析项目,以确保不会触发可能导致托管堆变得太大的其他托管分配。

最佳做法是仅禁用长期分配的垃圾回收器。例如,你可能希望在加载游戏关卡之前为游戏关卡分配所有必需的内存,然后禁用垃圾回收器以避免关卡期间的性能开销。关卡完成并释放所有内存后,您可以再次启用垃圾收集器并使用System.GC.Collect在加载下一级之前回收内存。

有关如何在运行时启用和禁用垃圾回收的更多详细信息,请参阅配置垃圾回收

其他资源

垃圾回收器概述
配置垃圾回收