我试图更深入地了解Java的垃圾回收。

在HotSpot JVM世代集合中,堆中有三个区域(Young代,Old代和永久代)。另外,有两种算法:

1)标记扫描紧凑型

2)并发标记和扫描

GC是否需要“停止运行”是否取决于它使用的算法而不是它运行的是哪一代?换句话说,如果我在所有三个区域上都使用1)作为GC算法,那么STW总是会发生吗?

另外,我了解不同之处在于第二种GC算法不需要压缩,最终会导致碎片化。那么第二个问题是为什么压缩需要STW暂停?

最佳答案

压缩导致STW暂停的关键原因如下,JVM需要移动对象并更新对其的引用。现在,如果您在更新引用和正在运行的应用程序之前移动对象,则可以从旧引用访问它,这会带来麻烦。如果您先更新引用,然后尝试移动对象,则更新的引用是错误的,直到对象被移动为止,而对象未移动时的任何访问都会引起问题。

对于CMS和Parallel收集器,年轻一代的收集算法都是相似的,并且它停止了运行,即在发生收集时停止了应用程序
JVM正在做的事情是,标记所有可以从根集中访问的对象,将这些对象从Eden移到幸存者空间,并将在集合中存活下来的对象超过使用期限的对象移到老一代。当然,JVM必须更新对已移动对象的所有引用。

对于较老的并行收集器,它在一个stop world(STW)阶段中完成所有标记,压缩和引用更新,这导致以GB为单位的堆暂停数秒。对于具有严格响应时间要求的应用程序来说,这是很痛苦的。直到现在,Paralle收集器仍然是用于吞吐量或批处理的最佳收集器(在Oracle Java中)。实际上,对于相同的场景,即使在并行收集器中暂停所花费的时间比CMS多,但我们仍能获得更高的吞吐量,但我认为这与压缩有关的更好的空间局部性有关。

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

G1GC计划替代CMS,并接受暂停目标。通过逐步压缩堆来解决碎片问题。尽管工作是增量的,所以您可以获得较小的暂停,但这可能会导致更频繁的暂停

在应用程序运行时,以上所有内容都不能压缩堆(CMS完全不压缩)。 AZUL GPGC垃圾回收甚至可以紧凑而无需停止应用程序,还可以处理引用更新。因此,如果您想深入了解GC的工作方式,则值得阅读GPGC的算法。 AZUL将其作为无间断的 Collection 家进行销售。

关于java - Java垃圾收集是否总是必须 “Stop-the-World”?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40182392/

10-09 16:38