0

我在带有 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 正在使用少量内存。

4

1 回答 1

5
java.lang.OutOfMemoryError: unable to create new native thread

我试图找出的是如何确定导致问题的原因,以便我可以对我们的代码进行适当的更改。

您的堆栈内存不足,无法分配更多线程。也可能是您用完了操作系统允许的最大进程数,但我不确定 Windows 是否有这样的限制。

默认情况下,在 64 位 JVM 中,每个线程的堆栈大小为 1M,并且 JVM 为线程堆栈分配了最大空间。你当然不想做这样的事情-Xss1G,这会给每个线程一个千兆字节。您可能会尝试-Xss128k降低每个线程的内存,但这看起来真的像一个创可贴。请参阅此页面:调整 Java 默认线程堆栈大小以节省内存

解决此问题的更好方法是限制使用固定大小的线程池创建的线程数,而不是为每个作业分叉一个线程。这在很大程度上取决于您的架构。如果您正在处理 Web 请求,则固定线程池将限制并发连接的数量,但可能会增加您的整体吞吐量。

请参阅Oracle 的线程池教程

问题是我们获得了具有大量可用操作系统内存 (RAM) 的 OOM。

是的,这些都是由 JVM 控制的非常具体的限制。这不是堆内存,JVM 不会增长到占用盒子上的所有内存。

请参阅以下链接:

于 2013-06-18T20:27:03.603 回答