我正在尝试更深入地理解 Java 的垃圾收集。
在HotSpot JVM分代收集中,堆中分为三个区域(年轻代、老年代和永久代)。此外,还有两种算法:
1) Mark Sweep Compact。
2) 并发标记和扫描。
GC 是否需要“Stop-the-world”取决于它使用的算法而不是它在哪一代运行,这是真的吗?换句话说,如果我在所有三个区域都使用 1) 作为 GC 算法,STW 总是会发生?
另外,我知道不同之处在于第二种 GC 算法不需要最终会导致碎片化的压缩。那么第二个问题就是为什么compaction需要STW暂停?
最佳答案
压缩导致STW暂停的关键原因如下,JVM需要移动对象并更新对它的引用。现在,如果您在更新引用和正在运行的应用程序之前移动对象,则从旧引用访问它会很麻烦。如果您先更新引用而不是尝试移动对象,则更新后的引用是错误的,直到对象被移动,并且在对象未移动时进行任何访问都会导致问题。
对于 CMS 和并行收集器,年轻代收集算法是相似的,它是停止世界,即应用程序在收集发生时停止 Stuff JVM 正在做的是,标记从根集可达的所有对象,将对象从伊甸园移动到幸存者空间,并将在集合中存活超过 tenuring 阈值的对象移动到老年代。当然,JVM 必须更新对已移动对象的所有引用。
老年代的并行收集器在单一停止世界 (STW) 阶段执行所有标记、压缩和引用更新,这导致以 GB 为单位的堆在几秒钟内暂停。这对于具有严格响应时间要求的应用程序来说是痛苦的。直到今天,Paralle 收集器仍然是吞吐量或批处理的最佳收集器(在 Oracle Java 中)。事实上,对于相同的场景,我们已经看到,即使在并行收集器中花费的时间比 CMS 花费的时间更多,我们仍然可以获得更高的吞吐量,我认为这与压缩带来的更好的空间局部性有关。
CMS通过并发做Marking解决了major collection中高停顿的问题。有 2 个 STW 部分,初始标记(从根集获取引用)和 Remark Pause(标记结束时的一个小 STW 暂停,用于在标记和应用程序同时工作时处理对象图中的更改)。对于几 GB 的堆大小和合理数量的应用程序线程,这两个暂停都在 100 -200 毫秒的范围内(记住更多的 Activity 线程更多的根)
G1GC 计划替代 CMS 并接受暂停目标。通过增量压缩堆来处理碎片。虽然工作是增量的,因此您可以获得更小的暂停,但这可能会以更频繁的暂停为代价
以上都不能在应用程序运行时压缩堆(CMS 根本不压缩)。 AZUL GPGC 垃圾收集甚至可以在不停止应用程序的情况下进行压缩,还可以处理引用更新。因此,如果您想深入了解 GC 的工作原理,那么阅读 GPGC 的算法是值得的。 AZUL 将其作为无暂停收集器进行营销。
关于java - Java Garbage Collect 是否总是必须为 "Stop-the-World"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40182392/