如何检测OutofMemoryError的原因?

我抱怨我的服务器应用程序在高负载时崩溃。
它是在Tomcat 5运行的Web应用程序。
我看到线程转储,我发现有一个OutOfMemory错误

1TISIGINFO转储事件“systhrow”(00040000)详情
“java / lang / OutOfMemoryError”“无法创建线程:retVal -1073741830,errno 12”>收到1TIDATETIME日期:2012/07/17 at 20:03:17 1TIFILENAME> Javacore文件名:C:\ ServerApplication \ Tomcat5 \ bin \ javacore.34545719.4646464.4172.0003.txt

堆信息如下:

 Maximum Java heap size : 1500m Initial Java heap size : 256m 

这是初始和最大堆大小的配置(32位java)

我也看到有可用的堆空间

 1STHEAPFREE Bytes of Heap Space Free: 2D19F3C0 1STHEAPALLOC Bytes of Heap Space Allocated: 5DC00000 

这是750MB的免费空间,对吧?

从线程方法分析我看到Threads的数量是695 ,其中49%java/lang/Object.wait(Native Method)39%sun/misc/Unsafe.park(Native Method)
另外我看到这个NO JAVA STACK 1%不确定这意味着什么。
0踏板也是死锁, 2%是Runnable。

我不确定如何解释这些信息或如何从这里继续检测根本原因。
对此有何帮助?

根据这篇文章 :

java.lang.OutOfMemoryError有两个可能的原因:无法创建线程消息:

  • 运行的线程太多,系统内部资源不足以创建新线程。
  • 系统已用完本机内存以用于新线程。 线程需要内部JVM结构的本机内存,Java™堆栈和本机堆栈。

所以这个错误可能与内存完全无关,只是创建了太多的线程……

编辑:

由于你有695个线程,你需要695倍的堆栈大小作为内存。 考虑到关于线程限制的这篇文章 ,我怀疑你正在尝试为可用的虚拟内存空间创建太multithreading。

您应该使用-XX:+HeapDumpOnOutOfMemoryError标志启动JVM。 生成OutOfMemoryError时,这将生成堆转储。

然后,正如@Steve所说,你可以使用像MAT这样的工具来分析转储并查看分配了哪些对象,以及谁保留对它们的引用。 这通常可以让您深入了解JVM耗尽内存的原因。

我知道你的意思,找到某个地方可能会让人感到困惑。

看看Eclipse Memory Analyzer (MAT)。 它将使用JHat将程序的内存快照转储到一个文件中,您可以重新打开和分析该文件。

此文件的浏览器非常巧妙地概述了程序创建的所有对象,您可以查看各种级别以查找是否存在可疑内容。


附上我的评论以回答……

当您的可执行 webapp崩溃时,将其转储到MAT。 MAT会告诉你多次创建的对象。 如果它是一个自定义对象,它经常是,它很容易找到。 如果没有,你可以看到它的父母,截断它,并从那里运行(抱歉图形的例子,我现在并不完全专注于SO :)。

哦,我忘了提,你可以在几个条件下多次运行程序,并且每次都进行转储。 然后,您可以分析趋势的每个转储。


但在我的情况下,我应该使用什么?我有一个在Tomcat中运行的Web应用程序

对不起,也错了。 如果我没弄错的话,MAT会转储JVM 进程 ,因此只要VM在你的盒子上运行,你就可以转储它的进程,看看发生了什么。


另一条评论突变为部分解决方案……

这比实际上变得更加困难。 说真的,这很简单,在你运行MAT一两次之后就可以了解事情。 运行你的应用程序直到事情崩溃。 转发它。 改变些什么。 运行,崩溃,转储。 重复。 然后,在MAT中打开转储,并比较看起来可疑的内容。

我学习这个时最棘手的部分是找到要转储的进程ID – 这仍然不是太麻烦。

IBM WebSphere上的类似消息显示了这一行

“无法创建线程:retVal”

作为本机OOM的指示,这意味着某个(进程的)线程正在尝试请求堆上的大部分内存。

上面的IBM链接有一系列步骤 – 其中一些是IBM特定的。 看一看。

从本机内存使用角度来看:

  • 最大Java堆设置
  • JDBC驱动程序
  • JNI代码或本机库
  • 垃圾收集未使用的类。 确保未设置-Xnoclassgc。
  • 线程池设置(固定大小的线程池)
  • 太多的类加载器等,但这些并不常见。
  • 来自javacores的类/类加载器的数量。

您可以看到的另一件事是PermGenSpace – 它有多大?

这个链接http://www.codingthearchitecture.com/2008/01/14/jvm_lies_the_outofmemory_myth.html建议

增加堆分配实际上会加剧这个问题! 它减少了编译器和其他本机组件必须使用的空间。 所以我的问题的解决方案是:1。减少分配给JVM的堆。 2.删除因未及时释放的本机对象而导致的内存泄漏。

您还在server.xml中为maxThreads配置了一个值吗? 默认值为200,但您的应用似乎有695?

固定

在创建新线程时遵循IBM技术说明java.lang.OutOfMemoryError ,特别是’ulimit’命令以增加默认值1024的值。

症状

 [2/25/15 12:47:34:629 EST] 00000049 SystemErr R java.lang.OutOfMemoryError: Failed to create a thread: retVal -1073741830, errno 11 [2/25/15 12:47:34:630 EST] 00000049 SystemErr R at java.lang.Thread.startImpl(Native Method) [2/25/15 12:47:34:630 EST] 00000049 SystemErr R at java.lang.Thread.start(Thread.java:936) [2/25/15 12:47:34:630 EST] 00000049 SystemErr R at org.eclipse.osgi.framework.internal.core.InternalSystemBundle.stop(InternalSystemBundle.java:251) [2/25/15 12:47:34:630 EST] 00000049 SystemErr R at com.ibm.ws.runtime.component.RuntimeBundleActivator.shutdownEclipse(RuntimeBundleActivator.java:54) [2/25/15 12:47:34:630 EST] 00000049 SystemErr R at com.ibm.ws.runtime.component.ServerCollaborator$ShutdownHook$1.run(ServerCollaborator.java:878) [2/25/15 12:47:34:630 EST] 00000049 SystemErr R at com.ibm.ws.security.auth.ContextManagerImpl.runAs(ContextManagerImpl.java:5459) [2/25/15 12:47:34:631 EST] 00000049 SystemErr R at com.ibm.ws.security.auth.ContextManagerImpl.runAsSystem(ContextManagerImpl.java:5585) [2/25/15 12:47:34:631 EST] 00000049 SystemErr R at com.ibm.ws.runtime.component.ServerCollaborator$ShutdownHook.run(ServerCollaborator.java:850) [2/25/15 12:47:34:631 EST] 00000049 SystemErr R at com.ibm.ws.runtime.component.ServerCollaborator$StopAction.alarm(ServerCollaborator.java:809) [2/25/15 12:47:34:631 EST] 00000049 SystemErr R at com.ibm.ejs.util.am._Alarm.run(_Alarm.java:133) [2/25/15 12:47:34:631 EST] 00000049 SystemErr R at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1815) 

环境

CentOS 6.6 64位IBM WAS 8.5.0.2 64位

参考

  • 设置ulimits的准则(WebSphere Application Server)