几个小时后垃圾收集器发疯了

时间:2012-09-27 13:22:38

标签: java jboss

我们的JBoss 3.2.6应用服务器出现了一些性能问题,在打开详细的GC日志记录并使用GCViewer分析这些日志后,我们注意到一段时间后(服务器重启后7到35小时)GC运行疯。似乎最初GC工作正常并且每小时左右做一次GC但是在某个时刻它开始疯狂并且每分钟执行完整的GC。因为这只发生在我们的生产环境中,所以无法尝试关闭显式GC(-XX:-DisableExplicitGC)或修改RMI GC间隔但是因为这发生在几个小时之后它似乎不是由知道引起的RMI GC问题。

有什么想法吗?

更新

我暂时无法发布GCViewer输出,但似乎根本没有达到最大堆限制。在GC疯狂之前,GC-ing就好了,但是当GC发疯时,堆不会超过2GB(最大24GB)。 除了RMI还有其他方法可以触发显式GC吗? (我检查了我们的代码,没有调用System.gc())

4 个答案:

答案 0 :(得分:2)

你的堆满了吗?有时,当VM可以释放足够的内存来防止真正的OutOfMemoryError但是不足以实际保持应用程序稳定运行时,VM会卡在“GC循环”中。

通常这会触发“OutOfMemoryError:超出GC开销限制”,但在此之前必须克服一定的阈值(在我的头顶上花费98%的CPU时间)。

您是否尝试过扩大堆大小?您是否检查过您的代码/使用了分析器来检测内存泄漏?

答案 1 :(得分:1)

您几乎肯定会发生内存泄漏,如果您让应用程序服务器继续运行它,最终会因OutOfMemoryException而崩溃。您需要使用内存分析工具 - 一个示例是VisualVM - 并确定问题的根源。通常,内存泄漏是由一些永远不会释放它们存储的对象引用的静态或全局对象引起的。

祝你好运!

更新

重读你的问题听起来事情很好然后突然你会遇到这种情况,GC正在努力回收空间。这听起来像是发生了一些消耗(并且不释放)大量堆的特定操作。

或许,正如@Tim建议的那样,你的堆需求正处于最大堆大小的阈值,但根据我的经验,你需要非常幸运地完全达到目标。无论如何,一些分析应该确定它是否是泄漏,或者你只需​​要增加堆的大小。

答案 2 :(得分:0)

除了您的应用程序中更可能发生内存泄漏事件外,还有其他1-2个原因。

在Solaris环境中,当我将几乎所有可用的4GB物理内存分配给JVM时,我曾经遇到过这样的问题,只留下大约200-300MB的操作系统。这导致VM进程在OS增加负载时突然交换到磁盘。解决方案不超过3.2GB。一个真正的角落案例,但也许与你的问题相同?

这导致GC活动增加的原因在于,大量交换会减慢JVM的内存管理速度,从而导致许多短暂的对象逃离幸存者空间,最终进入终身空间,这又占据了很多空间。更快。

答案 3 :(得分:0)

我建议何时发生 that you do a stack dump

我经常看到这种情况发生在线程群爆炸中。

无论如何看看堆栈转储文件,看看是什么运行。您可以轻松设置一些cron作业或监视脚本以定期运行jstack

您还可以比较堆栈转储的大小。如果它变得非常大,你就会有很多线程。

如果它没有变大,你至少可以看到哪些对象(调用堆栈)正在运行。

如果不起作用,你可以使用VisualVM或一些花哨的JMX废话,但首先要使用jstack,因为它易于使用。