为什么我会得到java.lang.OutOfMemory错误?

时间:2013-04-20 02:40:17

标签: java garbage-collection jvm

我有一个服务器通过套接字处理请求并生成一个线程来处理每个请求。

为什么我会得到一个java.lang.OutOfMemoryError,我该怎么做才能解决它?

2 个答案:

答案 0 :(得分:2)

类型I:堆空间不足。

这是最常见的错误。可能很难追踪,因为它涉及了解哪些对象是“正常”以及哪些对象应该被释放。

创建无限量的引用对象。创建特定于线程但被一个或多个全局对象引用的对象。

如果您可以重现此问题,请运行jmap -dump:format=b,file=output.bin

然后用jhat分析堆文件。

类型II:进程内存

如果您已经实现了JNI调用,或者JVM代表您创建了对象,那么 创建JNI对象,你可以用完进程内存,对于32位进程是4 gig。

正在运行的java进程的进程空间包括:

  • jvm memory
  • 已加载的库
  • 原生创建的对象

其中-Xmx仅控制JVM内存的大小。

类型III:垃圾收集器无法运行

我在任何网络搜索中都没有找到任何关于这种情况的参考。我想我已经阅读了解决java.lang.OutOfMemoryErrors的所有帖子。

如果你有一个java程序对本机代码进行JNI调用,那么当任何线程在JNI调用中时,垃圾收集器不会运行。给定一个足够繁忙的系统,在JNI调用中有两个或多个线程,垃圾收集器可能永远不会运行。

第一个实例是一个长时间运行的JNI调用,它调用java代码来释放当前对象并获取一个新对象。在每次迭代中,使用的内存量增加,未使用的对象不会被垃圾收集。

第二个实例是一个测试,其中每个生成的线程都会导致JNI调用。代码将运行很长一段时间,大约一个小时左右,但死了java.lang.OutOfMemoryError-Xloggc选项显示了前4000秒的定期垃圾回收,直到并发线程数增加为止。

4055.330: [GC 4055.330: [ParNew: 147424K->12220K(147456K), 0.0073372 secs] 769563K->637289K(1294336K) icms_dc=0 , 0.0073809 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]  
18668.710: [GC 18668.710: [ParNew: 143289K->16384K(147456K), 0.0297121 secs] 768358K->651851K(1294336K) icms_dc=0 , 0.0297604 secs]

[2014年6月7日更新] 在一个例子中,我发现这个答案Memory leak when calling java code from C using JNI解决了这个问题。 本地java内存被分配给C堆栈,即使它是在java中分配的,因为它是在JNI调用内部创建的。具体来说,我用PushLocalFrame()/ PopLocalFrame()包装了对java的反向调用以解决问题。

答案 1 :(得分:2)

发生内存不足时强制执行堆转储。见Can I force generation of a JVM crash log file?。然后使用其中列出的工具缩小内存泄漏: Tool for analyzing large Java heap dumps