Java Garbage Collect是否总是要“停止世界”?

时间:2016-10-21 17:30:32

标签: java algorithm garbage-collection

我试图更深入地理解Java的垃圾收集。

在HotSpot JVM世代集合中,在堆中,有三个区域(Young generation,Old generation和permanent generation)。此外,还有两种算法:

1) Mark Sweep Compact

2)并发标记和扫描

GC是否需要“Stop-the-world”取决于它使用的算法而不是它运行的是哪一代,这是真的吗?换句话说,如果我在所有三个区域使用1)作为GC算法,STW将永远发生?

另外,我理解不同的是第二个GC算法不需要压缩,最终会导致碎片。那么第二个问题就是为什么压缩需要STW暂停?

4 个答案:

答案 0 :(得分:13)

压缩导致STW暂停的关键原因如下,JVM需要移动对象并更新对它的引用。现在,如果您在更新引用之前移动对象,并且正在运行的应用程序从旧引用访问它而不是有问题。如果您首先更新引用并且尝试移动对象,则更新的引用是错误的,直到移动对象并且对象未移动时的任何访问都将导致问题。

对于CMS和Parallel collecter,年轻代收集算法是类似的,它停止了世界,即收集发生时应用程序停止 JVM正在做的事情是,标记从根集可到达的所有对象,将对象从Eden移动到幸存者空间,并将已经超过终点阈值的集合中的对象移动到旧代。当然,JVM必须更新所有已移动对象的引用。

对于旧一代并行收集器,在一个单一停止世界(STW)阶段进行所有标记,压缩和参考更新,这导致GB中的堆的暂停(以秒为单位)。对于具有严格响应时间要求的应用程序来说,这很痛苦。到目前为止,Paralle collector仍然是吞吐量或批处理的最佳收集器(在Oracle Java中)。事实上,我们已经看到了同样的情况,即使暂停所花费的时间多于并行收集器而不是CMS仍然可以获得更高的吞吐量,我认为这与更紧凑的空间局部性有关。

CMS通过同时执行标记解决了主要集合中的高暂停问题。有两个STW部分,初始标记(从根集中获取引用)和备注暂停(标记结束时的小STW暂停,以便在标记和应用程序同时工作时处理对象图中的更改)。对于几GB的堆大小和合理数量的应用程序线程,这两个暂停的范围都在100 -200毫秒范围内(记住更活跃的线程更多的根)

G1GC计划取代CMS并接受暂停目标。通过逐步压缩堆来处理碎片。虽然工作是增量的,但你可以得到更小的暂停,但这可能以更频繁的暂停为代价

在应用程序运行时,以上都不能压缩堆(CMS根本不压缩)。 AZUL GPGC垃圾收集甚至可以在不停止应用程序的情况下进行压缩,还可以处理参考更新。因此,如果您想深入了解GC如何工作,那么值得阅读GPGC的算法。 AZUL将其作为无停顿的收藏家推销。

答案 1 :(得分:6)

openjdk中所有免费提供的GC都有一些停止世界事件。而且不仅仅是GC,其他诸如去优化之类的东西也可以触发安全点。

但并非所有停顿都是平等的。 CMS和G1不需要使用旧代中的实时数据集来缩放其暂停时间,因为它们仅在暂停期间扫描对象的子集并且同时执行大部分工作,这与串行和吞吐量收集器不同。 / p>

正在进行一些工作来介绍another collector,这将进一步将暂停时间与实时数据集大小分离。

另外存在其他GC实现,其避免全局暂停 - 它们可能仍然经历每线程暂停 - 或使得暂停持续时间O(1),即独立于实时数据集大小。一个常用的例子是azul's C4 collector

  

所以第二个问题是为什么压缩需要STW暂停?

压缩意味着移动物体。移动对象意味着需要更新指针。当应用程序线程仍在运行时,这是非常困难或昂贵的。

并发算法通常会在吞吐量和复杂性方面付出一些代价,以换取较低的暂停时间。不进行压缩使得CMS相对(!)对于并发收集器来说很简单。

答案 2 :(得分:3)

这是一个链接,提供了有关java 8中不同收集器的一些很好的信息:https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/collectors.html#sthref27

所有策略都将停止世界。但是,您的性能要求可以促使您选择不同的GC策略来改善性能或响应时间。

答案 3 :(得分:0)

无论您选择哪种GC算法,都会出现Stop-the-world。 Stop-the-world意味着JVM正在阻止应用程序运行以执行GC。当stop-the-world发生时,除了GC所需的线程之外的每个线程都将停止它们的任务。