我认为这是因为 JVM 需要移动对象,对吗?
4 回答
首先,维基百科上的垃圾收集文章真的很不错。
一般来说,GC 不需要 Stop-the-World 暂停。有些 JVM 实现(几乎)是无暂停的(例如Azul Zing JVM)。每当 JVM 要求 STW 收集垃圾时,取决于它使用的算法。
Mark Sweep Compact (MSC)是 HotSpot 默认使用的流行算法。它以 STW 方式实现,分为 3 个阶段:
- MARK - 遍历活动对象图以标记可达对象
- SWEEP - 扫描内存以查找未标记的内存
- COMPACT - 重新定位标记的对象以对可用内存进行碎片整理
在堆中重定位对象时,JVM 应该更正对该对象的所有引用。在重定位过程中,对象图不一致,这就是为什么需要 STW 暂停。
并发标记扫描 (CMS)是 HotSpot JVM 中的另一种算法,它不利用 STW 暂停来收集旧空间(与完整收集不完全相同)。
CMS 正在利用写屏障(每次在 Java 堆中写引用时触发)来实现 MARK 的并发版本并且不使用 COMPACT。缺乏压缩可能会导致碎片,如果后台垃圾收集速度不够快,应用程序仍然会被阻塞。在这些情况下,CMS 将回退到 STW 标记-扫描-紧凑收集。
还有G1,它是 MSC 的增量变体。您可以在我的博客中阅读有关HotSpot JVM 中 GC 算法的更多信息。
使用吞吐量 GC,JVM 需要 STW 暂停以释放尽可能多的内存。只有使用这样的停顿才是最有效的。
使用低暂停收集器 (CMS),您可以同时清理老年代,而不会暂停您的应用程序。缺点是老年代变得支离破碎。如果它太碎片化并且需要压缩,则会发生 Full GC (STW)。但是,您始终可以调整您的应用程序,以免获得任何 Full GC。
G1 GC 是一个特例。它当前的主要目标是在堆上具有低碎片,同时仍然是并发的(如 CMS)。当它无法达到这个目标时,JVM 也会恢复到 STW 暂停,以便完全清理和压缩堆。
在几乎任何垃圾收集方案中,即使在大多数最小化暂停的方案中,都需要一个短暂的 stop-the-world 阶段来扫描堆栈上的引用。这个答案中的详细解释。增量和并发算法努力将这些暂停降至最低,但在大多数情况下仍然存在。
实际上,甚至有一些移动/压缩方法不需要在移动物体时停止世界(想到断奏)
stop-the-world 保证不会分配新对象,并且在收集器运行时对象不会突然变得不可访问。
优点是它比增量垃圾收集更容易实现和更快。