类型 I:堆空间不足。
这是最常见的错误。这可能很难追踪,因为它涉及了解哪些对象是“正常的”以及应该释放哪些对象。
创建无限数量的引用对象。创建特定于线程但被另一个全局对象引用的对象。
如果您可以重现该问题,请运行 jmap -dump:format=b,file=output.bin
然后用jhat分析堆文件。
类型 II:进程内存不足
如果您已经实现了 JNI 调用,或者有由 JVM 代表您创建的对象,那么
创建 JNI 对象时,您可能会耗尽进程内存,对于 32 位进程来说是 4 gig。
你正在运行的java进程的进程空间包括:
其中-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 的反向调用以解决此问题。