我们的应用程序中经常出现中断,基本上堆会随着时间的推移而增长,直到gc占用大量cpu时间并执行几分钟,从而大幅降低了应用程序的性能。该应用程序使用jsf和tomcat服务器。
同时,我们:
将堆大小从15g增加到26g(-xms27917287424-xmx27917287424)
采取几个堆转储(我们正试图使用这些转储来确定问题)
激活的gc日志
随着堆大小的增加,gc不会执行那么长的时间,但仍然需要大量cpu,并且会对应用程序进行frezes。
因此,问题是:
这正常吗?当gc执行时,它释放内存,所以我认为这可能不是内存泄漏(对吗?)
有没有一种优化gc的方法,或者这种行为只是应用程序本身出了问题的征兆?
我如何在不进行堆转储的情况下监视和分析它?
更新:我将jsf从2.2改为2.3,因为一些堆转储指出jsf使用了大量内存。这并没有奏效,昨天我们又一次中断了,但这次有点不同(从我的观点来看)。这一次,我们不得不重置tomcat,因为应用程序在一段时间后不再工作
在这种情况下,垃圾收集器在旧的gen堆未满时运行,而新一代gc一直在运行。是什么原因造成的?
1条答案
按热度按时间l5tcr1uw1#
正如评论中所说,申请的行为看起来并不不合理。您的代码不断地分配对象,导致堆空间被填满,从而导致gc运行。似乎没有内存泄漏,因为gc回收了大量空间,并且总体使用空间没有持续增加。
问题似乎在于,大量对象在被收集之前被提升到旧版本。由于对象的重新定位和重新Map(假设您使用的是压缩算法),主要gc周期在cpu方面更为昂贵。
为了减少这种情况,你可以尝试增加年轻一代的规模。当您增加了堆的总体大小,但增加的幅度不够时,就会发生这种情况。理想情况下,您希望在一个较小的gc周期内收集大多数对象,因为这实际上是免费的(在收集eden空间中的对象时,gc不会对它们进行任何处理)。您可以使用
-XX:NewRatio=
或-XX:NewSize=
旗帜。您还可以尝试更改幸存者空间大小,再次增加在使用期限之前收集的对象数量(使用-XX:SurvivorRatio=
这方面的标志)。对于监控,我发现飞行记录器和任务控制非常有用,因为您可以深入了解分配了多少特定类型的对象。连接到正在运行的jvm或进行转储以供以后分析也很容易。