CLR GC与JVM上最新的ZGC和Shenandoah GC相比如何?

问题描述

近年来,C#(在.NET世界中排名第一)中添加了许多功能,以减少GC压力。毫无疑问,所有这些功能使我们能够构建更好,更高效的应用程序。但是,无论随着时间的推移添加语言和VM(CLR,JVM)功能,高性能且无阻塞的GC都是托管应用程序的关键性能因素。

最近在JVM世界中,出现了两个新的GC,看来它们提供了卓越的指标。有一些来源(包括作者)提供了有关这些GC的基准和技术见解。我们可以了解到,“承诺”的最大STW(停止世界)时间间隔将不再是10 ms,并且无论堆大小如何,平均平均振荡时间都将低于1 ms。也有测试表明,新的GC开销是均衡的,不会对应用程序吞吐量产生负面影响,而与此同时,可大大减少(减少10倍或更多)STW暂停。

另一方面,关于CLR GC的信息很少。是否有最新的资料可以看到CLR GC(4.8,Core 3.1,.NET 5)与最新的JVM性能相比如何? 我可以找到一些讨论CLR GC与G1的较旧资料。但是今天的G1不能与ZGC / Shenandoah相提并论,而且旧的消息来源还没有显示出今天的现实。考虑到没有更新的数据源,我们可以得出结论,此后CLR GC指标并未显着改善。但这对于.NET平台在2020年似乎是一个真正的问题,因为平均STW约为20-30毫秒,偶尔会跳转到300+毫秒,相比于平均1毫秒和最大10毫秒,这看起来确实很糟糕(因为GC制造商声称并测试确认)在JVM上暂停。

我必须说这让我有些担心,因为在很多应用程序中,GC暂停很重要。实际上,它们是决定是​​否应将特定技术(例如.NET,JVM,native等)视为对某项任务或目的可行的关键因素之一。看起来JVM上的最新GC似乎为Java和其他JVM语言/技术打开了新领域。由于GC必须完成工作,因此我们不允许应用程序停止500ms左右的区域,而〜10ms的最大值(平均〜1ms)就足够了。

今天真相是什么? CLR GC与最新的JVM GC相比如何?是否有关于STW在CLR上暂停的任何保证(看来JVM朝这个方向发展)?

解决方法

这是一个很大的话题,但是如果我不得不总结一下:

  • shenandoah,zgc等都是低延迟垃圾收集器:它们牺牲吞吐量以确保非常短的暂停时间。它们适合于某种应用程序(基本上是具有低延迟约束的任何应用程序),但不适用于其他应用程序(举一个极端的例子,对于一批您根本不关心延迟并希望最大化吞吐量的应用程序,这使得这些GC是个不好的选择)
  • 到目前为止,.NET还没有低延迟GC。我听说有一些实施该计划的长期计划,但是我怀疑我们至少还要再等两年才能看到任何东西
  • .NET GC与Java GC有非常不同的方法。可以非常精细地调整Java GC,但要付出很大的代价。 .NET GC的目标是“工作正常”,设置很少,但易于理解和利用。事实并非如此,因为.NET Core添加了许多配置旋钮,例如用于调整第0代预算。

我们不允许在以下地区停止申请的区域 500毫秒左右,因为GC必须完成其工作,而GC最多约10毫秒 平均大约1毫秒就足够了。

根据我的非代表经验,使用.NET时,您可能希望每个gen 0集合的GC暂停时间在5到15毫秒之间。如果您的目标时间是〜1ms,则可能需要完全禁用GC。我知道有些公司正在.NET中进行高频交易,因此表明这是可能的。但这仅仅是因为他们有能力在市场开放时间之外重启服务器。如果您需要持续约1 ms的暂停时间,则.NET尚未为此做好准备。