最近,我们改进了应用程序的内存使用情况,在一些运行应用程序的服务器上增加了更多的RAM,但我们也开始切换到G1,希望使这些暂停不那么频繁和/或时间更短。事情似乎有所改善,但我们看到了一种以前没有发生过的奇怪行为(使用ParallelGC时没有出现):Perm Gen似乎很快就会填满,一旦达到最大值,就会触发完整的GC,这通常会导致应用程序线程长时间暂停(在某些情况下,超过1分钟)。
我们已经使用512 MB的最大perm大小几个月了,在我们的分析中,使用ParallelGC时,perm大小通常会停止增长约在390 MB左右。然而,我们切换到G1后,上述行为开始发生。我尝试将最大perm大小增加到1 GB甚至1.5 GB,但仍然会发生完整的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: [Full GC 2126M->670M(5120M), 23.6325510 secs] [Eden: 4096.0K(234.0M)->0.0B(256.0M) Survivors: 22.0M->0.0B Heap: 2126.1M(5120.0M)->670.6M(5120.0M)] [Times: user=10.16 sys=0.59, real=23.64 secs]
您可以在这里查看完整的日志here(从我们启动服务器的时刻开始,到完全GC几分钟后)。
以下是一些环境信息:
java版本"1.7.0_45"
Java(TM) SE运行时环境(构建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的预期行为?我在网上找到另一篇文章,有人质疑类永久代也应该执行增量收集,但没有得到答案...
我们的启动参数中是否有可以改进/纠正的地方?服务器有8GB内存,但似乎硬件不缺乏,应用程序的性能良好,直到触发完整GC时,用户会遇到大延迟并开始抱怨。