为什么JVM要进行如此多的垃圾回收?

4
以下是一个使用以下参数运行的JVM的jstat输出:
-Xmx10240m -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode 

jstat输出带有参数。

jstat -gcutil <pid> 10s

这段代码片段的执行时间为80秒,根据统计数据,其中将近70秒用于垃圾回收(GC)。这些都是触发的完全GC。

Timestamp   S0  S1  E       O       P       YGC     YGCT        FGC     FGCT        GCT         Diff
1040430.2   0   0   23.69   24.58   95.03   168048  22187.057   3672    4483.931    26670.988   8.175
1040440.2   0   0   0.1     24.58   95.02   168048  22187.057   3674    4495.551    26682.608   11.62
1040450.2   0   0   4.19    24.59   95.03   168048  22187.057   3677    4506.731    26693.788   11.18
1040460.2   0   0   0.01    24.45   95.02   168048  22187.057   3679    4517.391    26704.448   10.66
1040470.2   0   0   0.33    24.45   95.03   168048  22187.057   3681    4522.213    26709.27    4.822
1040480.2   0   0   0       24.43   95.02   168048  22187.057   3684    4534.816    26721.874   12.604

PermGen空间已经接近满了,但我认为Sun GC机制不会尝试在这里进行收集,并且我也看不出基于Eden或Old空间进行收集的原因。

有人能给我一些指示吗?可能发生了什么问题?

1个回答

3
这很可能是因为永久代占用率相当高。使用 CMS 算法时,仅当旧的或永久代占用率超过定义的阈值时,才会触发主要收集。除非我搞错了,默认的旧代占用率阈值为 68%,可以使用 -XX:CMSInitiatingOccupancyFraction=n 标志 进行更改。然而,在所提供的数据背景下,该值似乎无关紧要,因为在统计数据被记录时,旧代的占用率似乎低于 25%(这并不意味着旧代没有在此期间填满,但当永久代本身表现出更高的占用率时,这是不太可能的)。
请注意,默认情况下,CMS收集器不会从永久代中回收对象。这需要打开CMSClassUnloading标志。如果行为没有改善,则很可能永久代的大小不正确,并且需要为其分配更多内存,因为在每个主要收集周期上仅有少量永久代中的对象可进行回收。

请问您能否指出一下关于PermGen将由CMS算法收集的文档?如果没有明确设置CMSPermGenSweepingEnabled标志,我无法看到这种情况。 - bstick12
CMSPermGenSweepingEnabled 在 Java 6 中似乎已被弃用。尽管如此,大多数人仍使用 CMSClassUnloadingEnabledCMSPermGenSweepingEnabled 来启用 Java 6 中 Permgen 的收集。我能找到的关于这个行为的最接近文档是 OpenJDK 邮件列表 和 Sun bug 数据库中的 50370276250214 错误。 - Vineet Reynolds
接受这个答案,因为它似乎是最合理的解释。这个领域的文档非常差。 - bstick12
1
是的,文档很差。大多数人通过查看OpenJDK的源代码(与Sun/Oracle JVM相关)来了解标志。 - Vineet Reynolds

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接