为什么在 jstat -gcutil 的结果中显示的不是 FullGC,而是老一代从 99% 到 14%?

Why no FullGC but old gen from 99% to 14% display in results of the jstat -gcutil?

jstat -gcutil 如下图:

老一代先从13.78到99.98,再到14.81,但是FGCT一直是1, 为什么?

除了FullGC,还有其他原因造成这种情况吗?

GC是CMS和JVM参数:

-Xms4096m -Xmx4096m -Xss256k -XX:PermSize=256m -XX:MaxPermSize=256m -XX:NewSize=512m -XX:MaxNewSize=512m -XX:SurvivorRatio=16 -XX:+UseParNewGC -XX:ParallelGCThreads=16 -XX:MaxTenuringThreshold=32 -XX:+UseConcMarkSweepGC -XX:ParallelCMSThreads=8 -XX:+CMSParallelRemarkEnabled -XX:+CMSPermGenPrecleaningEnabled -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSCompactAtFullCollection

  1. 一次HotSpot JVM full GC在年轻代和永久代被收集时被统计...(来源:Analyzing the Performance Impact of Memory Utilization and Garbage Collection,goto主要与次要垃圾收集部分)

  2. 在不同的工具中 术语 "full garbage collection" 的用法存在歧义,有些工具不显示 GC 事件,有些则报告 gc 事件,如果运行 同时和同一个JVM。 如果你必须比较 output/reports,请记住这一点。

回到你的问题:

当我查看您的输出时,我发现永久 space 利用率正在增加。它从 19.59 开始,在输出的最后一行是 19.70。 直到那一刻才发生永久代 GC。这就是为什么FGC仍然是1的原因。

关于 jstats -gcutil 输出的一些附加说明。

  • O:旧 space 利用率,或如您所说的旧一代。
  • P:永久space利用率
  • YGC:年轻代垃圾回收计数
  • FGC:完整的垃圾收集计数
  • GCT:垃圾收集总时间。

. S0 S1 E O P YGC YGCT FGC FGCT GCT 12.44 0.00 27.20 9.49 96.70 78 0.176 5 0.495 0.672 12.44 0.00 62.16 9.49 96.70 78 0.176 5 0.495 0.672 12.44 0.00 83.97 9.49 96.70 78 0.176 5 0.495 0.672 0.00 7.74 0.00 9.51 96.70 79 0.177 5 0.495 0.673

YGC、YGCT、FGC 和 FGCT 的显示值指的是 Hotspot JVM 启动的时刻,而不是你启动 jstat -gcutil 的时刻。只是你想知道输出可能以例如开头的情况。第一行12个FGC。

这是 jstat 文档:Java 6 jstat doc

我自己做了一些测试,我的结论是当 运行 你的 JVM 参数时,它似乎是 jstat 中的一个错误。我 运行 jstat -gc 和 jstat -gcutil 同时在一个简单的测试应用程序上,我有以下输出:

jstat -gc:

S0C    S1C    S0U    S1U      EC       EU        OC         OU
29120,0 29120,0  0,0    0,0   466048,0 18642,2  3670016,0     0,0
29120,0 29120,0  0,0    0,0   466048,0 18642,2  3670016,0     0,0
29120,0 29120,0  0,0    0,0   466048,0 18642,2  3670016,0     0,0
29120,0 29120,0  0,0    0,0   466048,0 18642,2  3670016,0     0,0
29120,0 29120,0  0,0    0,0   466048,0 18642,2  3670016,0     0,0
29120,0 29120,0  0,0    0,0   466048,0 55926,2  3670016,0     0,0
29120,0 29120,0  0,0    0,0   466048,0 369663,6 3670016,0     0,0
29120,0 29120,0  0,0   29120,0 466048,0 466048,0 3670016,0   94773,6
29120,0 29120,0  0,0   29120,0 466048,0 299100,8 3670016,0   118478,6
29120,0 29120,0 29120,0  0,0   466048,0  9163,2  3670016,0   254498,6

jstat -gcutil

 S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT
  0,00   0,00   4,00   0,00   0,93      0    0,000     0    0,000    0,000
  0,00   0,00   4,00   0,00   0,93      0    0,000     0    0,000    0,000
  0,00   0,00   4,00   0,00   0,93      0    0,000     0    0,000    0,000
  0,00   0,00   4,00   0,00   0,93      0    0,000     0    0,000    0,000
  0,00   0,00   4,00   0,00   0,93      0    0,000     0    0,000    0,000
  0,00   0,00  26,00   0,00   0,97      0    0,000     0    0,000    0,000
  0,00   0,00  89,32   0,00   0,97      0    0,000     0    0,000    0,000
  0,00 100,00 100,00 100,00   0,97      1    0,000     0    0,000    0,000
  0,00 100,00  80,02   3,23   0,97      1    0,905     0    0,000    0,905
100,00   0,00  13,76   6,93   0,97      2    1,441     0    0,000    1,441

如您所见,当 运行 -gcutil 跳转到 100 时,我的 Old 使用了,即使应用程序刚刚开始填充 old gen。 jstat -gc 显示老一代几乎完全是空的。该应用程序非常简单,只需填充一个 HashMap,为什么当 jstat -gcutil 这么说时,老一代不可能 100% 满。