压缩导致STW暂停的关键原因如下,JVM需要移动对象并更新对它的引用。现在,如果您在更新引用之前移动对象,并且正在运行的应用程序从旧引用访问它,那么就会遇到麻烦。如果先更新引用,然后尝试移动对象,则更新的引用是错误的,直到对象被移动,并且在对象未移动时的任何访问都会导致问题。
对于CMS和并行收集器来说,年轻一代收集算法是相似的,它是停止世界,即当收集发生时应用程序停止 JVM正在做的事情是,标记所有可以从根集访问的对象,将对象从伊甸园移动到幸存者空间,并将收集中幸存下来的对象移动到旧一代。当然,JVM 必须更新对已移动对象的所有引用。
对于老一代并行收集器来说,在单个停止世界(STW)阶段中完成所有标记,压缩和参考更新,这导致以GB为单位的堆在几秒钟内暂停。对于具有严格响应时间要求的应用程序来说,这是痛苦的。到目前为止,Paralle收集器仍然是吞吐量或批处理方面最好的收集器(在Oracle Java中)。事实上,我们已经看到,对于相同的场景,即使暂停时间比CMS在并行收集器中花费的时间更多,我们仍然可以获得更高的吞吐量,我认为这与由于压缩而具有更好的空间局部性有关。
CMS通过同时进行标记解决了主要收集中高暂停的问题。有2个STW部分,初始标记(从根集获取引用)和备注暂停(标记结束时的一个小STW暂停,以处理标记和应用程序同时工作时对象图中的更改)。这两个暂停都在100 -200毫秒的范围内,对于几GB的堆大小和合理的应用程序线程数(记住更多的活动线程更多的根)
G1GC计划取代CMS并接受暂停的目标。通过增量压缩堆来处理碎片。虽然工作是渐进的,所以你可以得到更小的暂停,但这可能是以更频繁的暂停为代价的。
上述任何一种都不能在应用程序运行时压缩堆(CMS 根本不压缩)。AZUL GPGC 垃圾回收甚至可以在不停止应用程序的情况下进行压缩,还可以处理引用更新。因此,如果您想深入了解GC的工作原理,那么值得一读GPGC的算法。AZUL将其作为无暂停的收藏家进行销售。