为什么Go语言可以将GC暂停时间降低到低于1毫秒,而JVM却不能?

huangapple go评论86阅读模式
英文:

Why Go can lower GC pauses to sub 1ms and JVM has not?

问题

这是链接:https://groups.google.com/forum/?fromgroups#!topic/golang-dev/Ab1sFeoZg_8

> 今天我提交了对垃圾收集器的更改,使得典型的最坏情况下的停顿时间小于100微秒。这应该特别改善具有许多活跃goroutine的应用程序的暂停时间,之前这可能会显著增加暂停时间。

高GC暂停是JVM用户长期以来一直在努力解决的问题。

是什么(架构上的?)限制阻止了JVM将GC暂停降低到Go的水平,但不影响Go呢?

英文:

So there's that: https://groups.google.com/forum/?fromgroups#!topic/golang-dev/Ab1sFeoZg_8:

> Today I submitted changes to the garbage collector that make typical worst-case stop-the-world times less than 100 microseconds. This should particularly improve pauses for applications with many active goroutines, which could previously inflate pause times significantly.

High GC pauses are one of the things JVM users struggle with for a long time.

What are the (architectural?) constraints which prevent JVM from lowering GC pauses to Go levels, but are not affecting Go?

答案1

得分: 37

2021更新:随着OpenJDK 16的推出,ZGC的最大暂停时间小于1毫秒,平均暂停时间为50微秒。

它在执行压缩的同时实现了这些目标,这与Go的垃圾收集器不同。

更新:随着OpenJDK 17的推出,Shenandoah利用了ZGC引入的相同技术,并取得了类似的结果。

> 有哪些(架构上的?)限制阻止了JVM将GC暂停降低到与Go语言相同的水平?

实际上并没有根本性的限制,因为低暂停的垃圾收集器已经存在一段时间了(请参见下文)。因此,这可能更多是基于历史经验或开箱即用配置的不同印象。

> JVM用户长期以来一直在与高GC暂停作斗争。

通过一些搜索可以发现,Java也有类似的解决方案:

  • Azul提供了一个无暂停收集器,可以扩展到100GB+的规模。
  • Redhat正在向OpenJDK贡献Shenandoah,Oracle贡献ZGC
  • IBM提供了Metronome,也旨在实现微秒级的暂停时间。
  • 还有其他各种实时JVM。

与Go语言不同,OpenJDK中的其他收集器都是紧凑的分代收集器。这样做是为了避免碎片问题,并通过启用碰撞指针分配和减少GC中的CPU时间来提供更高的吞吐量,以适应具有大堆的服务器级机器。在良好的条件下,CMS(Concurrent Mark Sweep)即使与移动的年轻代收集器配对,也可以实现单位毫秒级的暂停。

Go语言的垃圾收集器是非分代的、非紧凑的,并且需要写屏障(参见这个其他的SO问题),这导致了较低的吞吐量/更高的收集CPU开销,更高的内存占用(由于碎片和需要更多的余量)以及堆上对象的非高速缓存有效放置(非紧凑内存布局)。

因此,Go的垃圾收集器主要针对暂停时间进行了优化,同时相对简单(按照垃圾收集标准),但牺牲了其他性能和可扩展性目标。JVM的垃圾收集器做出了不同的权衡。早期的垃圾收集器通常注重吞吐量。而较新的垃圾收集器在实现低暂停时间和其他目标时牺牲了更高的复杂性。

英文:

2021 Update: With OpenJDK 16 ZGC now has a max pause time of <1ms and average pause times 50µs

It achieves these goals while still performing compaction, unlike Go's collector.

Update: With OpenJDK 17 Shenandoah exploits the same techniques introduced by ZGC and achieves similar results.


> What are the (architectural?) constraints which prevent JVM from lowering GC pauses to golang levels

There aren't any fundamental ones as low-pause GCs have existed for a while (see below). So this may be more a difference of impressions either from historic experience or out-of-the-box configuration rather than what is possible.

> High GC pauses are one if the things JVM users struggle with for a long time.

A little googling shows that similar solutions are available for java too

  • Azul offers a pauseless collector that scales even to 100GB+
  • Redhat is contributing shenandoah to openjdk and oracle zgc.
  • IBM offers metronome, also aiming for microsecond pause times
  • various other realtime JVMs

The other collectors in openjdk are, unlike Go's, compacting generational collectors. That is to avoid fragmentation problems and to provide higher throughput on server-class machines with large heaps by enabling bump pointer allocation and reducing the CPU time spent in GC. And at least under good conditions CMS can achieve single-digit millisecond pauses, despite being paired with a moving young-generation collector.

Go's collector is non-generational, non-compacting and requires write barriers (see this other SO question), which results in lower throughput/more CPU overhead for collections, higher memory footprint (due to fragmentation and needing more headroom) and less cache-efficient placement of objects on the heap (non-compact memory layout).

So GoGC is mostly optimized for pause time while staying relatively simple (by GC standards) at the expense of several other performance and scalability goals.
JVM GCs make different tradeoffs. The older ones often focused on throughput. The more recent ones achieve low pause times and several other goals at the expense of higher complexity.

答案2

得分: 0

根据这个演示文稿《Getting to Go: The Journey of Go's Garbage Collector》,Go语言的垃圾收集器只利用堆的一半来存储活跃数据:

堆的大小是活跃堆的两倍

我个人的印象是,Java的垃圾收集器通常会追求更高的堆利用率,所以在这方面它们做出了非常不同的权衡。

英文:

According to this presentation, Getting to Go: The Journey of Go's Garbage Collector, the Go collectors only utilize half of the heap for live data:

> Heap 2X live heap

My impression is that Java GCs generally aim for higher heap utilization, so they make a very different trade-off here.

huangapple
  • 本文由 发表于 2016年10月29日 18:40:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/40318257.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定