如何检测OutofMemoryError的原因?

Jim*_*Jim 10 java debugging multithreading tomcat out-of-memory

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

1TISIGINFO转储事件"systhrow"(00040000)详细信息
"java/lang/OutOfMemoryError""无法创建线程:retVal -1073741830,错误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
Run Code Online (Sandbox Code Playgroud)

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

我也看到有可用的堆空间

1STHEAPFREE    Bytes of Heap Space Free: 2D19F3C0   
1STHEAPALLOC   Bytes of Heap Space Allocated: 5DC00000
Run Code Online (Sandbox Code Playgroud)

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

而从线程方法分析我看到的线程数是695的这49%java/lang/Object.wait(Native Method)39%sun/misc/Unsafe.park(Native Method)
另外我看到这个NO JAVA STACK 1%不知道是什么意思.
0踏板也是死锁的并且2%是Runnable.

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

ben*_*y23 9

根据这篇文章:

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

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

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

编辑:

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


Fla*_*vio 7

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

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


Ben*_*Ben 5

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

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

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


附上我的评论以回答......

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

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


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

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


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

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

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