在我们公司中,我们使用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选项如下:
我们使用的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之前记录的错误(它们记录的时间是几小时或几分钟之前),之前没有任何内容,之后也没有。
我觉得很奇怪它没有报告内存部分(Java堆大小或Permgen Space)。
也许内存堆保留太大了,JVM无法写入,因为它处于临界状态(OOM)? 也许JMX参数搞砸了一些东西?
这是当前正在运行的JVM的VisualVM截图:
更新:
我在另一个tomcat安装上安装了相同版本的Web应用程序(与出现问题的版本相同并且相同的Java选项),该Web应用程序被修改为通过无限循环中的arraylist来手动引发OOM。 测试证明了Java选项-XX:+HeapDumpOnOutOfMemoryError有效,因为在我引发OOM后产生了内存转储;但在这种情况下,错误是:
java.lang.OutOfMemoryError: Java Heap space
跟着堆栈跟踪看,似乎问题不在于我的JVM参数标记,而是与我遇到的特定错误类型有关。
另一个奇怪的地方是,在我的测试中抛出OOM错误后,该应用程序仍然在Tomcat中正常工作。然而,在我的原始问题中,OOM会导致Tomcat服务停止。
可惜没有在它停止之前进行堆栈跟踪,看起来进一步调查很困难。 :(