我们有一个相当大的应用程序在 JBoss 7 应用服务器上运行。过去,我们使用 ParallelGC,但它在一些堆很大(5 GB 或更多)且通常几乎被填满的服务器上给我们带来了麻烦,我们会经常遇到很长的 GC 暂停。
最近,我们改进了应用程序的内存使用,并在少数情况下为运行应用程序的一些服务器添加了更多 RAM,但我们也开始切换到 G1,希望减少这些暂停的频率和/或更短。事情似乎有所改善,但我们看到了一个以前没有发生过的奇怪行为(使用 ParallelGC):Perm Gen 似乎很快就被填满了,一旦达到最大值,就会触发 Full GC,这通常会导致长时间的停顿在应用程序线程中(在某些情况下,超过 1 分钟)。
几个月来,我们一直在使用 512 MB 的最大 perm 大小,在我们的分析过程中,使用 ParallelGC 时,perm 大小通常会停止增长到 390 MB 左右。然而,在我们切换到 G1 之后,上述行为开始发生。我尝试将最大 perm 大小增加到 1 GB 甚至 1.5 GB,但仍然会发生 Full GC(它们只是不太频繁)。
在此链接中,您可以看到我们正在使用的分析工具(YourKit Java Profiler)的一些屏幕截图。请注意,当触发 Full GC 时,Eden 和 Old Gen 有很多可用空间,但 Perm 大小是最大的。在 Full GC 之后,Perm 的大小和加载的类的数量急剧减少,但它们又开始上升并重复循环。代码缓存很好,永远不会超过 38 MB(在这种情况下是 35 MB)。
这是 GC 日志的一部分:
2013-11-28T11:15:57.774-0300:64445.415:[完整 GC 2126M->670M(5120M),23.6325510 秒] [伊甸园:4096.0K(234.0M)->0.0B(256.0M) 幸存者:22.0M- >0.0B 堆:2126.1M(5120.0M)->670.6M(5120.0M)] [时间:用户=10.16 系统=0.59,实际=23.64 秒]
您可以在此处查看完整的日志(从我们启动服务器的那一刻起,直到完整 GC 后的几分钟)。
以下是一些环境信息:
java版本“1.7.0_45”
Java(TM) SE 运行时环境 (build 1.7.0_45-b18)
Java HotSpot(TM) 64 位服务器 VM(内部版本 24.45-b08,混合模式)
启动选项:-Xms5g -Xmx5g -Xss256k -XX:PermSize=1500M -XX:MaxPermSize=1500M -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintAdaptiveSizePolicy -Xloggc:gc.log
所以这是我的问题:
这是 G1 的预期行为吗?我在网上找到另一个帖子,有人质疑非常相似的事情,并说 G1 应该在 Perm Gen 上执行增量收集,但没有答案......
我们的启动参数有什么可以改进/纠正的吗?服务器有 8 GB 的 RAM,但我们似乎并不缺乏硬件,应用程序的性能很好,直到触发完整的 GC,这就是用户体验大滞后并开始抱怨的时候。