Java Spring 应用 + Tomcat:JVM 不生成内存转储文件

4
在我们公司中,我们使用Spring(Flex前端)开发企业Web应用程序,并以SAAS方式将此应用程序部署到Tomcat 6中提供给客户使用。最近,我们遭遇了(貌似)随机的OutOfMemory错误,因此在调查后,我知道我们应该在出现错误时检查JVM的内存转储。
我们使用的JVM版本是1.6.18,Tomcat版本是Tomcat 7.0.23,运行在Windows Server 2008下。我在Tomcat监视面板(Java选项卡下)中添加了参数-XX:+HeapDumpOnOutOfMemoryError,但机器没有产生任何转储文件。我们正在调查的服务器上设置了完整的Java选项如下:
-Dcatalina.home=C:\Program Files\Apache Software Foundation\Tomcat 7.0
-Dcatalina.base=C:\Program Files\Apache Software Foundation\Tomcat 7.0
-Djava.endorsed.dirs=C:\Program Files\Apache Software Foundation\Tomcat 7.0\endorsed
-Djava.io.tmpdir=C:\Program Files\Apache Software Foundation\Tomcat 7.0\temp
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Djava.util.logging.config.file=C:\Program Files\Apache Software Foundation\Tomcat 7.0\conf\logging.properties
-XX:PermSize=128m
-XX:MaxPermSize=1024m
-Xms1024m
-Xmx6144m
-XX:+HeapDumpOnOutOfMemoryError
-Dcom.sun.management.jmxremote.port=3333
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false 

如您所见,最大堆大小非常大(6个Gigs),因为我们的应用程序特别重。我添加了JMX参数以进行测试,以便使用VisualVM实时查看JVM状态,但是当我观察它时没有发生任何事情。

stderr只显示了这个:

java.lang.OutOfMemoryError

oom 除了其他我不知道是否相关但在OOM之前记录的错误(它们记录的时间是几小时或几分钟之前),之前没有任何内容,之后也没有。

我觉得很奇怪它没有报告内存部分(Java堆大小或Permgen Space)。

也许内存堆保留太大了,JVM无法写入,因为它处于临界状态(OOM)? 也许JMX参数搞砸了一些东西?

这是当前正在运行的JVM的VisualVM截图: VisualVM

更新:

我在另一个tomcat安装上安装了相同版本的Web应用程序(与出现问题的版本相同并且相同的Java选项),该Web应用程序被修改为通过无限循环中的arraylist来手动引发OOM。 测试证明了Java选项-XX:+HeapDumpOnOutOfMemoryError有效,因为在我引发OOM后产生了内存转储;但在这种情况下,错误是:

java.lang.OutOfMemoryError: Java Heap space

跟着堆栈跟踪看,似乎问题不在于我的JVM参数标记,而是与我遇到的特定错误类型有关。

另一个奇怪的地方是,在我的测试中抛出OOM错误后,该应用程序仍然在Tomcat中正常工作。然而,在我的原始问题中,OOM会导致Tomcat服务停止。

可惜没有在它停止之前进行堆栈跟踪,看起来进一步调查很困难。 :(


为什么不使用jvisualVm创建内存转储?(您可以使用MAT研究内存转储中的泄漏 - 它是免费的) 或者在将应用程序部署到tomcat并监视关闭和打开应用程序时使用它,这样您就可以看到所有线程是否正在关闭。 - aurelius
@aurelius 感谢您的评论。我目前正在使用 VisualVM,并且知道我可以从中制作转储,但是我想要的是在 OOM 发生时进行转储(-XX:+HeapDumpOnOutOfMemoryError 选项应该能做到这一点)。几天前,我尝试使用 VisualVM 进行转储并使用 MAT 查看它,但没有成功(我补充说我不确定在分析转储时应该看哪里,通常我会查看可疑的内存泄漏和支配树)。 - frankieta
我相信你已经检查过了,但还是要问一下:你的磁盘上有足够的空间(大约6 GB)来存储堆转储文件吗? - Khanna111
是的 @Khanna111GauravKhanna,有很多空间 :) - frankieta
1个回答

0
在您的JVM参数中添加-XX:HeapDumpPath="/some/path/dump.out"以明确设置堆转储文件位置。

好的,下次我们重新启动Tomcat时,我们将尝试明确设置转储路径(但这对我来说似乎从未是问题,因为在我们的本地机器上,即使没有指定路径,堆转储也会被创建)。 谢谢Amir。 - frankieta
是的,我怀疑这不是路径问题,但我还是尝试指定它,但没有成功。不过还是谢谢。我进行了另一个测试,已在我的问题更新中描述。 - frankieta
@AmirAfghani 我的JVM参数与你的相同,还有堆转储路径。具体来说: -....catalina属性... -XX:PermSize=128m -XX:MaxPermSize=1024m -Xms1024m -Xmx6144m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath="C:/" -Dcom.sun.management.jmxremote.port=3333 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false 程序在我的C分区写入转储文件后终止。 这是控制台输出的信息:java.lang.OutOfMemoryError: Java heap space Dumping heap to C:/\java_pid7996.hprof ... - frankieta
请将“C:/”更改为“C:/dump.out”。您确定您的程序对C:有写入权限吗? - Amir Afghani
@AmirAfghani,是的,我的应用程序有写入C:的权限,因为我的第二个测试应用程序(旨在崩溃并出现OOM错误的应用程序)刚刚成功地将.hprof转储文件写入了C:分区。我想我们将不得不使用一些诊断软件,如New Relic或类似软件,来帮助我们理解这里发生了什么。谢谢。PS:抱歉我的评论回复有所延迟...圣诞节时间。 - frankieta
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接