java - Java Garbage Collect 是否总是必须为 "Stop-the-World"?

标签 java algorithm garbage-collection

我正在尝试更深入地理解 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/

相关文章:

java - 如何在 RequestParams 中传递 int 参数?

java - 在 Java 中禁用 Outlook 电子邮件转发

java - 为什么向 BorderPane 添加另一个元素会弄乱我的格式?

algorithm - 测量两台机器之间的链路质量

performance - 为什么 Spark 应用程序在 MaxGCPauseMillis 较低的情况下运行速度会慢很多?

java - 通过用户点击进行碰撞检测

java - 最小优先级队列的复杂性问题

c++ - 找到上信封的最大长度

java - 对于想要最小化常规 Sun/Oracle Hotspot JVM 上的 GC 延迟的实时系统,最佳的 GC 和内存配置是什么?

python - Python GC 也会关闭文件吗?