我在带有 64 位 JVM 的 64 位 Windows 7 和 Server 2008 中运行,并且在一个有大量可用内存的程序中出现“java.lang.OutOfMemoryError:无法创建新的本机线程”。我一直在阅读有关垃圾收集和堆生成等的内容,但似乎没有任何东西可以解释这种情况。我最接近的是一个条目,它提供了一个分配空闲线程的程序(How to hit java.lang.OutOfMemoryError by spawning threads?根据 Ajay George 的回应),并且至少重现了我们在生产代码中遇到的问题。问题是我们得到的 OOM 有大量可用的 OS 内存 (RAM),堆中分配的内存很少,并且当我们使用 -XX:+HeapDumpOnOutOfMemoryError 运行时没有响应 OOM 异常。当使用小堆设置 (Xmx16M) 和大堆栈设置 (Xss1G) 运行上面的代码(空闲线程生成器)时,java 进程在失败前分配了大约 8179 个线程,并且在任务管理器中查看时具有较大的提交大小,但其他比它声称的资源很少。
我已经打开了 GC 跟踪,并且在失败之前观察到很少的活动(通常是两个 GC)。我提升了 PermGen 无济于事。我将初始堆大小提高到在失败之前没有被消耗的点(Xms1024M Xmx65536M),它仍然会出现 OOM。
我已经使用 YourKit 分析器查看了这两个,它准确地显示了我所怀疑的,即堆没有被消耗并且很少发生 GC。
然而,我在生产中遇到的问题只有大约 150-300 个线程(它会有所不同),当它失败并且堆栈大小是默认值时,所以在 Windows 中可能是 1M。
我试图找出的是如何确定导致问题的原因,以便我可以对我们的代码进行适当的更改。
在创建内存源非常有限的线程时,JVM 有什么特别之处吗?我知道,对于 NIO 和内存映射文件,JVM 不会跟踪后台内存支持,并且内存映射中的高水平搅动将很快耗尽内存,但在这种情况下,操作系统会显示 JVM 对内存的使用. 在我们的线程案例中,操作系统显示 JVM 正在使用少量内存。