Java 为什么CMS垃圾收集器不使用整个CPU

Java 为什么CMS垃圾收集器不使用整个CPU,java,garbage-collection,Java,Garbage Collection,在《Java性能权威指南》一书中,对吞吐量垃圾收集器和CMS垃圾收集器的CPU利用率进行了比较,如下所示: 吞吐量收集器(默认情况下)将消耗100%的CPU 可在机器运行时使用,因此更精确 此测试期间CPU使用情况的表示如图所示 5-2. 大多数情况下,只有应用程序线程在运行, 消耗总CPU的25%。当GC启动时,100%的CPU被占用 消耗。因此,实际CPU使用量类似于锯齿模式 在图表中,即使测试期间的平均值报告为 直线虚线的值 在并发收集器中,当存在 与应用程序同时运行的后台线程 线程。在

在《Java性能权威指南》一书中,对吞吐量垃圾收集器和CMS垃圾收集器的CPU利用率进行了比较,如下所示:

吞吐量收集器(默认情况下)将消耗100%的CPU 可在机器运行时使用,因此更精确 此测试期间CPU使用情况的表示如图所示 5-2. 大多数情况下,只有应用程序线程在运行, 消耗总CPU的25%。当GC启动时,100%的CPU被占用 消耗。因此,实际CPU使用量类似于锯齿模式 在图表中,即使测试期间的平均值报告为 直线虚线的值

在并发收集器中,当存在 与应用程序同时运行的后台线程 线程。在这种情况下,CPU的图形可能如图5-3所示

应用程序线程使用总CPU的25%启动。 最终,它为CMS后台线程创建了足够的垃圾 踢进来;该线程还消耗整个CPU,带来 总数高达50%。当CMS线程完成时,CPU使用率下降到25%, 等等请注意,没有100%的CPU峰值周期,这是一个 稍微简化一点:将有非常短的尖峰 CMS年轻一代收集期间100%的CPU使用率,但 它们足够短,我们可以在讨论中忽略它们


我知道当吞吐量垃圾收集器运行时,它会停止所有应用程序线程,而CMS垃圾收集器会与其他应用程序线程同时运行,但我不明白为什么当吞吐量收集器启动时,它会使用整个CPU周期,并将CPU利用率提高到100%,但当CMS收集器启动时,它会留下50%的CPU未使用的?是否有任何东西阻止CMS collector使用所有可用的CPU资源?

由于CMS collector同时执行某些工作,因此其设计不使用所有可用的系统资源,而更像是后台任务。这在更大程度上适用于G1和ZGC

因为并行采集器是同步的,所以它被设计为使用所有可用的系统资源来尽快完成工作。

我喜欢这种与现实几乎没有联系的虚构图形;然后
CMS
java-14
中被弃用和删除,仅供参考。到目前为止,我还不是GC专家,但作为免责声明,我喜欢摆弄不同的代码实现(尤其是在
Shenandoah
codebase中)

想想看:当你停止这个世界,把每一条线都拖到一个拖车上去做
GC
,你的首要任务就是要做得快,非常快。由于找出什么是垃圾并将其移动到清除区域是一项CPU受限的任务,因此您需要尽可能多的CPU和尽可能多的线程来执行这项任务。因此,
CMS
以及另一个采集器,在其
STW
暂停中,将使CPU达到最大值,以便更快地完成工作。由于吞吐量收集器根本没有任何并发暂停,这些峰值可能更明显。相比之下,
CMS
中的某些阶段是并发的,因此CPU利用率在图形上可能不太明显

还值得注意的是,某些垃圾收集器会故意降低应用程序的运行速度。它们可以降低“mutator”(应用程序)线程的优先级,并从GC实现本身提升线程的优先级
Shenandoah
调用这个“调整”,当分配率太高,GC线程无法处理时,它就会这样做


但我要重复一次,这是一个虚构的图表,对CPU利用率的真正理解和正确结论是非常重要的。

谢谢你回答了我的问题,但我遇到了另一个问题:我们现在CMS的CPU利用率应该高于吞吐量,为什么在这种情况下CMS的总体CPU利用率不高?@Tashkhishi收集器采用的并发级别越高,其总体消耗的系统资源就越高。