为什么 java8 GC 超过 11 小时没有收集?

Why does the java8 GC not collect for over 11 hours?

上下文:64 位 Oracle Java SE 1.8.0_20-b26

在超过 11 个小时的时间里,我的 运行 java8 应用程序一直在累积 Tenured 代中的对象(接近 25%)。所以,我手动点击了jconsole中的Perform GC按钮,你可以看到图表右侧的堆内存急剧下降。我没有打开任何特殊的 VM 选项,除了 XX:NewRatio=2

为什么GC不清理老年代?

Why does the GC not clean up the tenured generation ?

因为不需要。

看起来您的应用程序正在以相对较慢的速度累积永久垃圾,并且仍然有大量 space 用于永久对象。 "throughput" 收集器通常仅在 space 填满时运行。就 CPU 使用而言,这是最有效的……这是吞吐量收集器优化的目的。

简而言之,GC 正在按预期工作。

如果您担心正在使用的内存量(因为没有收集永久 space),您可以尝试 运行 使用较小堆的应用程序。但是,该图表明应用程序的初始行为可能与其稳态行为有很大不同。换句话说,您的应用程序可能 需要 一个大堆作为开始。如果是这种情况,那么减小堆大小可能会使应用程序停止工作,或者至少会使启动阶段变慢很多。

这是完全符合预期且需要的行为。 JVM 一直通过及时执行 Minor GC 成功地避免了 Major GC。根据定义,Minor GC 不会触及终身代,分代垃圾收集器背后的关键思想正是这种模式将会出现。

您应该对您的应用程序的运行情况感到非常满意。

正如其名称所示,吞吐量收集器的主要目标是吞吐量(通过 GCTimeRatio)。它的次要目标是暂停时间 (MaxGCPauseMillis)。只有 tertiary goal 它才考虑保持低内存占用。

如果您想实现较小的堆大小,则必须放宽其他两个目标。

您可能还想降低 MaxHeapFreeRatio 以允许 JVM 将内存返回给 OS。