在过去的几天里,我们看到我们服务器上的JVM进入一个状态,他们在OldGen的GC中花费100%的CPU时间,时间:
一个。他们不需要,因为堆上有足够的空间和
B中。他们没有回收任何东西。
我知道他们在GC中是通过查看堆栈跟踪并将ProcessExplorer中的ThreadID与堆栈转储中的ThreadID相关联。每个GC线程占用大约4%的CPU。
服务器运行16 gig堆(32gig物理RAM)&有8个核心。正常运行时间通常为30天左右,只需要根据MS补丁要求重新启动,但目前它们在20天内崩溃。
这是持续时间,时间范围= 19天的图表。 http://i45.tinypic.com/257qalu.png
这是该图尾部的缩放 http://i48.tinypic.com/2duiccw.png
如您所见,持续时间急剧增加。
这是GC后堆使用情况的图表。 http://i48.tinypic.com/znna4h.png
如果这是典型的内存泄漏,我希望看到橙色峰值越来越高,直到它们不再达到峰值,但是如图所示,剩下的堆空间很大。
我已经为每台服务器获得了堆转储,并且没有任何突出的问题。有几个ehCache商店,我可以看到我们的应用程序代码,即只是"正常的东西"
我们在20天前做出的最大改变是实现了一个供应商补丁,该补丁将内部缓存从使用硬引用(和明显的内存泄漏)的无界散列映射改为由软引用和放大器组成的散列映射。我想知道这是否是原因,也就是说,在某一点之后管理这些软引用会产生巨大的开销?
有没有人想知道接下来要去哪里,或者有人可以证实我的软参考理论?
这是我的jvm.args:
java.args = -server -Xms16000m -Xmx16000m -Dsun.io.useCanonCaches = false -XX:MaxPermSize = 350m -Xloggc:e:/gcLogs/eRGCLogs.txt -verbose:gc -XX:+ PrintGCDetails -XX:+ PrintGCTimeStamps -XX:+ PrintGCDateStamps -XX:+ UseParallelGC -XX:+ UseParallelOldGC -Dnet.sf .ehcache.sizeof.filter = d:/jo3/java_ehCacheOpenSource/sizeOfExclusions.config -Xbatch -Dcoldfusion.rootDir = {application.home} /../ -Dcoldfusion.libPath = {application.home} /../ lib -Dcoldfusion.classPath = {application.home} /../ lib / updates,{ application.home} /../ lib中,{} application.home /../网关/ LIB / {application.home} /../的wwwroot / WEB-INF /柔性/罐,{application.home} /。 ./wwwroot/WEB-INF/cfform/jars,d:/jo3/java,d:/JO3/java_ehCacheOpenSource/,D:/jo3/java_ehCacheMonitorProbe
我们在Coldfusion上,这有点像一个位于java之上的庞大框架。
JVM版本:1.6.0_29
根据要求,"正常" GC日志看起来像:
2013-03-19T22:11:36.670 + 1100:1288665.702:[GC [PSYoungGen:4695800K-> 471119K(4722112K)] 9301727K-> 5077046K(15644800K),0.3584434 secs] [次:用户= 5.01 sys = 0.00,实= 0.36秒] 2013-03-19T22:14:55.078 + 1100:1288864.099:[GC [PSYoungGen:4722063K-> 498009K(4783104K)] 9327990K-> 5103936K(15705792K),0.3766889 secs] [次:用户= 5.37 sys = 0.00,真实= 0.38秒] 2013-03-19T22:17:46.749 + 1100:1289035.760:[GC [PSYoungGen:4654489K-> 517299K(4673792K)] 9260416K-> 5123227K(15596480K),0.4130828 secs] [次:用户= 5.80 sys = 0.00,实际= 0.41秒] 2013-03-19T22:21:08.762 + 1100:1289237.763:[GC [PSYoungGen:4673779K-> 522660K(4738880K)] 9279707K-> 5143831K(15661568K),0.4005516 secs] [次:用户= 5.97 sys = 0.00,真实= 0.40秒] 2013-03-19T22:23:42.683 + 1100:1289391.675:[GC [PSYoungGen:4582628K-> 530998K(4590976K)] 9203799K-> 5186242K(15513664K),0.4317352 secs] [次:用户= 6.24 sys = 0.00,实际= 0.43秒] 2013-03-19T22:26:11.096 + 1100:1289540.080:[GC [PSYoungGen:4590966K-> 518331K(4724096K)] 9246210K-> 5206959K(15646784K),0.3914401 secs] [次:用户= 5.99 sys = 0.00,实际= 0.39秒] 2013-03-19T22:27:44.076 + 1100:1289633.055:[GC [PSYoungGen:2602730K-> 447527K(4732864K)] 7291358K-> 5208743K(15655552K),0.3725317 secs] [次:用户= 5.80 sys = 0.00,真实= 0.37秒] 2013-03-19T22:27:44.448 + 1100:1289633.428:[全GC(系统)[PSYoungGen:447527K-> 0K(4732864K)] [ParOldGen:4761215K-> 4628296K(10922688K)] 5208743K-> 4628296K( 15655552K)[PSPermGen:352378K-> 352287K(352832K)],4.2955639 secs] [次:用户= 57.70 sys = 0.06,real = 4.30 secs] 2013-03-19T22:30:37.950 + 1100:1289806.920:[GC [PSYoungGen:4004416K-> 70948K(4690432K)] 8632712K-> 4699245K(15613120K),0.1062227 secs] [次:用户= 0.76 sys = 0.00,实际= 0.11秒] 2013-03-19T22:33:27.154 + 1100:1289976.115:[GC [PSYoungGen:4054116K-> 109175K(4092352K)] 8682413K-> 4737472K(15015040K),0.1347919 secs] [次:用户= 1.03 sys = 0.00,真实= 0.13秒] 2013-03-19T22:36:32.120 + 1100:1290161.070:[GC [PSYoungGen:4092343K-> 147318K(4712320K)] 8720640K-> 4775615K(15635008K),0.1593523 secs] [次:用户= 1.58 sys = 0.00,真实= 0.16秒] 2
当我们处于故障模式时,GC日志看起来像:
2013-03-22T10:03:47.619 + 1100:1504185.901:[GC [PSYoungGen:0K-> 0K(5452736K)] 4413907K-> 4413907K(16375424K),0.0114248 secs] [次:用户= 0.16 sys = 0.00,实= 0.01秒] 2013-03-22T10:03:47.631 + 1100:1504185.912:[Full GC [PSYoungGen:0K-> 0K(5452736K)] [ParOldGen:4413907K-> 4412613K(10922688K)] 4413907K-> 4412613K(16375424K)[ PSPermGen:358399K-> 358278K(358400K)],5.4435442 secs] [次:用户= 73.74 sys = 0.14,real = 5.44 secs] 2013-03-22T10:03:53.145 + 1100:1504191.426:[GC [PSYoungGen:269219K-> 7734K(5449088K)] 4681833K-> 4422114K(16371776K),0.0298728 secs] [次:用户= 0.34 sys = 0.00,实际= 0.03秒] 2013-03-22T10:03:53.175 + 1100:1504191.456:[Full GC [PSYoungGen:7734K-> 0K(5449088K)] [ParOldGen:4414379K-> 4415189K(10922688K)] 4422114K-> 4415189K(16371776K)[ PSPermGen:358399K-> 358371K(358400K)],2.6033684 secs] [次:用户= 36.33 sys = 0.00,real = 2.60 secs] 2013-03-22T10:03:55.788 + 1100:1504194.069:[GC [PSYoungGen:94969K-> 826K(5451328K)] 4510158K-> 4416015K(16374016K),0.0133588 secs] [次:用户= 0.16 sys = 0.00,实= 0.01秒] 2013-03-22T10:03:55.802 + 1100:1504194.082:[Full GC [PSYoungGen:826K-> 0K(5451328K)] [ParOldGen:4415189K-> 4415348K(10922688K)] 4416015K-> 4415348K(16374016K)[ PSPermGen:358399K-> 358389K(358400K)],2.7156884 secs] [次:用户= 38.11 sys = 0.00,real = 2.71 secs] 2
答案 0 :(得分:5)
正如许多人在评论中提到的那样,PermGen中的空间不足很可能是你的原因。这可能是因为整个代码中的字符串过多实际导致PermGen“爆炸” - 也加载了很多类(通常通过在后台为你做的框架)也可能导致这种情况。
此外,正如上面提到的评论之一 - 使用CMS集合(并发标记和扫描)可以减少您的停止世界 GC,假设问题与旧一代的容量有关。它还可以通过减少延迟来提高您的性能,无论当前问题如何,这都是好的。
另外,如果您发布GC日志的片段,这有助于指向正确的方向。
关于 jstat 工具,您可以按以下方式使用它来获取有用的信息:
jstat -gcutil <pid> <interval>
我通常使用1000毫秒的间隔。 -gcutil
为您提供GC利用率(以%为单位) - 因此您可以查看是否有任何一代接近100%。
您还可以使用jstat -gc <pid> ...
并获得老一代的确切容量。
编辑:查看GC日志后
根据您的GC日志,它确认了您的PermGen正在填满的原始前提。 在 10:03:47 和 10:03:55 之间的时间范围内,我可以看到PermGen不断达到它的最大值而且GC不知何故在10-100左右移除KB数据:
见下文:
2013-03-22T10:03:47.631+1100: 1504185.912: [Full GC [... [PSPermGen: 358399K->358278K(358400K)]...
2013-03-22T10:03:53.175+1100: 1504191.456: [Full GC [... [PSPermGen: 358399K->358371K(358400K)]...
2013-03-22T10:03:55.802+1100: 1504194.082: [Full GC [... [PSPermGen: 358399K->358389K(358400K)]...
如果你看看老一代和年轻一代你可以看到它们都没有达到它们的最大值,OldGen在10GB中消耗了4GB - 所以它不是原因。
根据您收集的数据,我无法判断PermGen填充的速度是否与流程的正常运行时间一致 - 这意味着PermGen看起来应该在一天内填满,而不是20天。所以很难说什么是明确的解决方案,但这里有一些建议:
String
的{{1}}方法 - 如果您在代码中使用它过于宽泛,这可能是您的根本原因。