增量式快照功能_功能预览:增量垃圾收集

增量式快照功能_功能预览:增量垃圾收集

增量式快照功能

We have just added an experimental new feature to Unity 19.1a10: Incremental Garbage Collection. Read this post to learn what this feature is all about, how it can help your project, what all our future plans for it and how can you get involved in the process.

我们刚刚在Unity 19.1a10中添加了实验性的新功能:增量垃圾收集。 阅读这篇文章,以了解此功能的全部内容,它如何为您的项目提供帮助,我们未来的所有计划以及您如何参与该过程。

为什么要增加GC? (Why incremental GC?)

The C# language uses managed memory with automated garbage collection, meaning that it uses an automatic method of tracking objects in memory and releasing the memory of any object which is no longer needed (See our documentation for more info). The benefit of this is that you generally don’t need to manually keep track of releasing any memory which you don’t need anymore because the garbage collector will automatically do that for you, which makes your work easier and also removes a big source of potential bugs. The downside is that the garbage collector takes some time to do its work, and this may happen in moments when you would rather not want to spend time on this.

C#语言将托管内存与自动垃圾回收一起使用,这意味着它使用一种自动方法来跟踪内存中的对象并释放不再需要的任何对象的内存(有关更多信息,请参见我们的文档 )。 这样做的好处是您通常不需要手动跟踪释放不再需要的任何内存,因为垃圾收集器会自动为您执行此操作,这使您的工作更加轻松,并且消除了潜在的错误。 缺点是垃圾收集器需要一些时间来完成其工作,而这可能是在您不想在此上花费时间的时候发生的。

Unity uses the Boehm–Demers–Weiser garbage collector which is a stop-the-world garbage collector, meaning that whenever it needs to perform garbage collection, it will stop the running program, and only resume normal execution once it has finished all its work. This can cause delays in the execution of the program at somewhat arbitrary moments, which can take anywhere between less than 1 and several 100 milliseconds, depending on how much memory the garbage collector needs to process and on the platform the program is running on. Now, obviously, for real-time applications like games, this can become quite a big issue, as it isn’t possible to sustain a consistent frame rate as required for smooth animation if the program’s execution can be arbitrarily suspended by the garbage collector. These interruptions are also known as GC spikes, as they will show as spikes in an otherwise smooth profiler frame time graph. Usually, developers try to work around this issue by writing their code to avoid creating “garbage” memory while running the game, so the garbage collector has less work to do – but this isn’t always possible or easy.

Unity使用Boehm–Demers–Weiser垃圾收集器 ,这是一个世界各地的垃圾收集器,这意味着每当需要执行垃圾收集时,它将停止正在运行的程序,并且仅在完成所有工作后才恢复正常执行。 这可能会导致程序在某些任意时刻延迟执行,这可能需要不到1到几百毫秒的时间,具体取决于垃圾收集器需要处理多少内存以及程序在运行平台上。 现在,显然,对于像游戏这样的实时应用程序,这可能会成为一个很大的问题,因为如果垃圾回收器可以任意暂停程序的执行,那么就无法保持平滑动画所需的一致帧速率。 这些中断也称为GC尖峰,因为它们将在否则平滑的探查器帧时间图中显示为尖峰。 通常,开发人员尝试通过编写代码来解决此问题,以避免在运行游戏时创建“垃圾”内存,因此垃圾收集器要做的工作较少-但这并不总是可能或容易的。

Enter Incremental Garbage Collection. With Incremental GC, we still use the same Boehm–Demers–Weiser GC, but we run it in an incremental mode, which allows it to split its work into multiple slices. So instead of having a single long interruption of your program’s execution to allow the GC to do its work, you can have multiple, much shorter interruptions. While this will not make the GC faster overall, it can significantly reduce the problem of GC spikes breaking the smoothness of the animation by distributing the workload over multiple frames.

输入增量垃圾收集。 对于增量GC,我们仍然使用相同的Boehm–Demers–Weiser GC,但是我们以增量模式运行它,从而可以将其工作分成多个部分。 因此,您可以有多个更短的中断,而不必长时间中断程序的执行以允许GC完成其工作。 虽然这不会使GC整体上更快,但可以通过将工作负载分布在多个帧上来显着减少GC尖峰破坏动画平滑度的问题。

To understand the impact of this, check these screenshots from the Unity Profiler of a little GC performance test script, running as a macOS Standalone build, without and with incremental GC enabled. The script is running at 60 fps. The light blue parts of the frame are “script operations” (simulated by a System.Threading.Thread.Sleep call in the script), the yellow parts are Vsync (ie, waiting for the next frame to begin), and the dark green parts are garbage collection.

要了解其影响,请从Unity Profiler中的一些GC性能测试脚本中检查这些屏幕截图,该脚本作为macOS Standalone构建运行,未启用增量GC。 该脚本以60 fps的速度运行。 框架的浅蓝色部分是“脚本操作”(由脚本中的System.Threading.Thread.Sleep调用模拟),黄色部分是Vsync(即,等待下一帧开始),深绿色部分是垃圾收集。

Without incremental GC (above), the project shows spikes of around 30ms every few seconds, interrupting the otherwise smooth 60fps frame rate.

在没有增量GC的情况下(上图),该项目每隔几秒钟显示大约30ms的峰值,从而中断了原本平稳的60fps帧速率。

With incremental GC (above), the same project keeps its consistent 60fps frame rate, as the GC operation is broken up over several frames, using only a small time slice of each frame.

使用增量式GC(如上),由于GC操作分为几帧,而每个帧仅占用一小段时间,因此同一项目将保持其一致的60fps帧速率。

This screenshot shows the same project, also running with incremental GC enabled, but this time with fewer “scripting operations” per frame. Again, the GC operation is broken up over several frames. The difference is that this time, the GC uses more time each frame, and requires fewer total frames to finish. This is because we adjust the time allotted to the GC based on the remaining available frame time if Vsync or Application.targetFrameRate is being used. This way, we can run the GC in time which would otherwise be spent waiting, and thus get GC “for free”.

此屏幕快照显示了在启用增量GC的情况下运行的同一项目,但是这次每帧的“脚本操作”较少。 同样,GC操作被分解为几个帧。 所不同的是,这次,GC每帧占用更多时间,并且需要更少的总帧来完成。 这是因为如果使用了VsyncApplication.targetFrameRate,我们会根据剩余的可用帧时间来调整分配给GC的时间。 这样,我们可以及时运行GC,否则本该花时间等待,从而“免费”获得GC。

如何启用增量GC? (How to enable incremental GC?)

Incremental GC is currently supported in Unity 2019.1 alpha on Mac, Windows and Linux Standalone Players and on iOS, Android and Windows UWP players. More supported platforms will be added in the future. Incremental GC requires the new .NET 4.x Equivalent scripting runtime version.

目前在Mac,Windows和Linux独立播放器以及iOS,Android和Windows UWP播放器的Unity 2019.1 alpha中支持增量GC。 将来将添加更多受支持的平台。 增量GC需要新的.NET 4.x等效脚本运行时版本。

On supported configurations, Incremental GC is now available as an experimental option in the “Other settings” area of the Player settings window. Just enable the Use incremental GC (Experimental) checkbox, and build a player to give it a try.

在受支持的配置上,现在可以在“播放器设置”窗口的“其他设置”区域中将Incremental GC作为实验选项使用。 只需启用“使用增量GC(实验性)”复选框,然后构建一个播放器即可尝试。

You can get more precise control over incremental GC behavior using the new Scripting.GarbageCollector APIs added in 2019.1.

您可以使用2019.1。中添加的新Scripting.GarbageCollector API对增量GC行为进行更精确的控制。

Once you’ve tested it on your project, please let us know how it went on the forum – we’d love to hear your feedback!

在您的项目中对其进行测试后, 请让我们知道它在论坛上的进展情况 -我们很乐意听到您的反馈!

预期成绩 (Expected results)

If you enable incremental GC, the garbage collector will split up the garbage collection work across multiple operations, which can then be distributed across multiple frames. We hope that in most cases where GC spikes were an issue, this will mitigate the symptoms. But Unity content is extremely diverse and can behave in very different ways – and it’s likely that there are cases where incremental GC may not be beneficial.

如果启用增量GC,则垃圾收集器会将垃圾收集工作拆分为多个操作,然后可以将其分布在多个框架中。 我们希望在大多数情况下出现GC尖峰的情况,这将减轻症状。 但是Unity的内容千差万别,并且行为方式也可能非常不同-在某些情况下,增量GC可能不会带来好处。

Specifically, when incremental GC breaks up its work, the part which it breaks up is the marking phase, in which it scans all managed objects to find which other objects they reference, to track which objects are still in use. This assumes that most of the references between objects don’t change between slices of work. When they do change, the objects which have been changed need to be scanned again in the next iteration. This can cause a situation where incremental collection never finishes because it will always add more work to do – in this case, the GC will fall back to doing a full, non-incremental collection. It’s easy to create artificial test cases changing all the references all the time, where incremental GC will perform worse than non-incremental GC.

具体来说,当增量GC中断工作时,它中断的部分是标记阶段,在该阶段,它将扫描所有托管对象以查找它们引用的其他对象,以跟踪仍在使用的对象。 假设对象之间的大多数引用在工作片之间不会更改。 当它们确实发生更改时,需要在下一次迭代中再次扫描已更改的对象。 这可能会导致增量收集永远不会完成的情况,因为它总是会增加更多工作要做–在这种情况下,GC会退回到进行完整的非增量收集。 创建人工测试案例很容易始终更改所有引用,增量式GC的性能将比非增量式GC差。

Also, when using incremental GC, Unity needs to generate additional code (known as write barriers) to inform the GC whenever a reference has changed (so the GC will know if it needs to rescan an object). This adds some overhead when changing references which can have a measurable performance impact in some managed code.

另外,在使用增量GC时,只要引用发生更改,Unity需要生成其他代码(称为写障碍)来通知GC(这样GC就会知道是否需要重新扫描对象)。 更改引用时,这会增加一些开销,这可能会对某些托管代码产生可衡量的性能影响。

Still, we believe that most typical Unity projects (if there is such a thing as “typical” Unity projects) can benefit from incremental GC, especially if they were suffering from GC spikes.

不过,我们认为,大多数典型的Unity项目(如果有“典型” Unity项目之类的东西)可以从增量GC中受益,尤其是当它们遭受GC峰值的困扰时。

实验状态 (Experimental status)

Incremental GC is included in Unity 2019.1 as an experimental preview feature. This has been done for a number of reasons:

增量GC作为实验性预览功能包含在Unity 2019.1中。 这样做的原因有很多:

  • It isn’t yet supported on all platforms.

    目前尚不支持所有平台。
  • As outlined in the “Expected Results” section above, we expect incremental GC to be beneficial or at least not detrimental performance-wise for most Unity content, and this seems to have been true for various projects we have been testing with. But as Unity content is very diverse, we want to make sure that this assumption stays true across the greater Unity ecosystem, and we need your feedback on this.

    如上文“预期结果”部分所述,对于大多数Unity内容,我们期望增量GC对性能有益或至少无害,这对于我们正在测试的各种项目来说似乎都是正确的。 但是由于Unity的内容非常多样化,我们希望确保在整个更大的Unity生态系统中这一假设都成立,我们需要您的反馈。
  • The requirement for Unity code and scripting VM (mono, il2cpp) to add write barriers to inform the GC whenever references in managed memory have changed introduces a potential source of bugs where we have missed adding such a write barrier, which could lead to objects being Garbage Collected when they are still needed. Now, we have done extensive testing (both manual and automated) and we aren’t aware of any such issues, and we believe that this feature is stable (otherwise, we would not ship it). But, once again, because of the diversity of Unity content and because such bugs might turn out to be hard to trigger in practice, we cannot completely rule out the possibility that there may be issues.

    要求Unity代码和脚本VM(mono,il2cpp)添加写壁垒以在托管内存中的引用发生更改时通知GC,这会导致潜在的错误源,而我们却错过了添加这种写壁垒的可能,这可能导致对象仍需要时收集的垃圾。 现在,我们已经进行了广泛的测试(手动和自动),并且我们没有发现任何此类问题,并且我们相信此功能是稳定的(否则,我们将不发货)。 但是,再一次,由于Unity内容的多样性,并且由于实际上在实践中很难触发此类错误,因此我们无法完全排除存在问题的可能性。

So, overall we believe that this feature works as expected and there are no known issues with it. But, because of the complexity of the Unity ecosystem, we need some time and exposure to get the confidence to drop the experimental label, which we will do based on the feedback we get.

因此,总的来说,我们认为此功能可以按预期运行,并且没有已知问题。 但是,由于Unity生态系统的复杂性,我们需要一些时间和精力来放下删除实验标签的信心,我们将根据收到的反馈意见进行此操作。

未来的计划 (Future plans)

Incremental GC is available in Unity 2019.1 alpha now, but we expect a few changes to the feature in the course of the next year.

增量GC现在可以在Unity 2019.1 alpha中使用 ,但我们预计明年会对该功能进行一些更改。

  • Add support for all other player platforms

    添加对所有其他播放器平台的支持
  • Remove experimental label (this depends on your feedback)

    移除实验标签(这取决于您的反馈)
  • Add support for running the Editor itself in incremental GC mode.

    添加对在增量GC模式下运行编辑器本身的支持。
  • Make incremental GC the default option (this depends on your feedback)

    将增量GC设置为默认选项(这取决于您的反馈)

为什么不使用[插入名称] GC? 我听说这真的很好! (Why did you not use [insert name] GC instead? I heard it’s really good!)

When discussing incremental GC, we’re often asked why we haven’t considered using some other GC solution instead of Boehm GC, for instance Xamarin’s Sgen GC. We have considered other options (including writing our own GC) and will continue to do so, but the main reason for staying with Boehm and switching that to incremental mode instead is that this seems to be the safest step we can do while still getting significant improvements. As explained in the “Experimental Status” section above, one of the risks is introducing bugs due to missing or incorrectly placed write barriers. But the requirement of adding write barriers is shared by pretty much any GC solution more modern than what Unity uses today. So by staying with Boehm GC, we can somewhat isolate the risk created by having to add write barriers correctly from the risk of also switching to a completely different GC.

在讨论增量GC时,经常会问我们为什么不考虑使用其他一些GC解决方案而不是Boehm GC,例如Xamarin的Sgen GC。 我们已经考虑了其他选项(包括编写自己的GC),并将继续这样做,但是与Boehm呆在一起并将其切换为增量模式的主要原因是,这似乎是我们可以做的最安全的步骤,同时仍然变得很重要改进。 如上面“实验状态”部分所述,其中一项风险是由于缺少或未正确放置写障碍而引入错误。 但是,几乎任何比Unity现在使用的现代方案都要多的GC解决方案都对添加写屏障的要求有共同的要求。 因此,通过使用Boehm GC,我们可以在一定程度上隔离因必须正确添加写障碍而导致的风险,以及从切换到完全不同的GC的风险。

We will continue to watch developments in this area, and see how your needs develop with the introduction of incremental Boehm. If we will find that incremental Boehm still leaves a lot of our users struggling to deal with GC spikes or other issues, we will consider other options.

我们将继续关注这一领域的发展,并通过引入增量Boehm来了解您的需求如何发展。 如果我们发现增量Boehm仍然使我们的许多用户都在努力解决GC峰值或其他问题,我们将考虑其他选择。

So, once again, your feedback is important, so please check out the alpha and let us know what you think on the forum!

因此,再次,您的反馈很重要,因此请查看Alpha,在论坛上告诉我们您的想法!

翻译自: https://blogs.unity3d.com/2018/11/26/feature-preview-incremental-garbage-collection/

增量式快照功能