java.lang.OutOfMemoryError:无法创建新的本机线程 at java.lang.Thread.start0(Native Method) at java.lang.Thread.start(Unknown Source)
操作系统是Windows 7 64位 我们正在运行32位JVM(1.7.0_45)
使用Windows任务管理器,我可以看到该进程有39个本机线程(不是很多),因此我们的应用程序没有线程泄漏...没有其他进程消耗大量线程(Explorer有35个,jvisualvm有24个,iexplore有20个,...我没有确切的数量,但是总体用户可能使用的线程数可能只有300个左右)。
我已经尝试连接JVisualVM,但它无法连接到该进程(可能是由于线程耗尽)。但从JVisualVM可以获取的指标来看,Java线程数量约为22个活动线程和11个守护线程。
堆表现良好-堆大小为500MB,实际使用了250MB。
该进程使用-Xmx512m启动。
我们的进程在任务管理器中显示的内存使用量为597,744K。
工作站有8GB RAM,其中只使用了3.8-4.0GB(我知道,32位进程无法访问所有RAM,但仍然有足够的空间)。
使用VMMap,堆栈大小为49,920KB,已提交2,284K。
该进程显示5358KB可用,而自由列表中最大可分配块的大小为1,024K。
我使用资源监视器,它显示的提交(KB)为630428,工作集(KB)为676,996,可共享(KB)为79,252,私有(KB)为597,744。
我完全不知道这里发生了什么。我已经阅读了很多关于此问题的文章,听起来在一些Linux系统上,每个用户线程有一个限制,可能会导致问题(但这不是Linux,并且其他文章中描述的问题通常需要数千个线程-绝对不是我们这里的情况)。
如果我们的堆确实很大,我可以看到它会占用线程可用的空间,但是500MB似乎是一个非常合理且小的堆(特别是对于拥有8GB RAM的工作站)。
所以我已经尽我所能做的一切 - 有人对这里可能发生的事情有任何额外的指针吗?
编辑1:
我发现了这篇有趣的文章:Eclipse crashes with "Unable to create new native thread" - any ideas? (my settings and info inside)。
他们认为堆栈大小可能是问题。
这篇文章:where to find default XSS value for Sun/Oracle JVM? - 给出了一个指向Oracle文档的链接,说明默认的堆栈大小是512KB。因此,如果我的应用程序有大约40个线程,那么我们正在查看20 MB的堆栈。500MB堆。所有这些似乎都在32位Java进程的正常范围内。
所以我能想到的只有两种可能性:
- 某些短暂的条件导致大量线程被创建(但这些线程在我们进行诊断之前就被丢弃了)
- 内存分段出现问题。有趣的是,每个VMMap中可分配的最大块(1MB)似乎并不多......在另一台正常工作的机器上,最大可分配块为470MB......
那么,有没有关于如何检查内存分段的指针?
编辑2:
@mikhael链接的文章(http://blog.egilh.com/2006/06/2811aspx.html)提供了32位JVM允许的线程数量的粗略计算。
我将假设:
OS进程空间限制:2GB 现代JVM需要250MB(这是一个很大的假设-我只是将链接文章中的数字加倍) 堆栈大小(默认Oracle):512KB 堆:512MB PermGen:(记不清确切数字,但肯定少于100MB,所以就用那个数字吧)
所以我有一个最坏的情况:(2GB - .25GB - .5GB - .1GB)/.005GB = 230个线程
编辑3:
我应该最初包含的信息:应用程序在此问题发生之前可以正常运行很长时间(如24到48小时)。该应用程序进行持续的后台处理,因此空闲时间非常少。不确定是否重要...
编辑4:
更多信息:从另一个失败中查看VMMap,我看到本机堆耗尽。
堆大小为1.2GB,仅提交了59.8MB。
Java运行时可能是问题所在,或者可能存在某些未正确释放的本机资源问题?例如可能是未被释放的内存映射文件?
我们确实使用内存映射文件,因此我将把重点放在这些文件上。
编辑4:
我认为我已经追踪到问题所在,即出现以下异常:
java.lang.OutOfMemoryError
at java.util.zip.Deflater.init(Native Method)
at java.util.zip.Deflater.<init>(Unknown Source)
at java.util.zip.Deflater.<init>(Unknown Source)
at java.util.zip.DeflaterOutputStream.<init>(Unknown Source)
at java.util.zip.DeflaterOutputStream.<init>(Unknown Source)
at ....
在一些非常少的流(我现在有4个例子)中,我们正在进行压缩,发生了上述情况。当它发生时,VMMap会将进程的堆(不是JVM堆,而是实际的本地堆)增加到2GB。一旦发生这种情况,一切都崩溃了。这现在非常可重复(将相同的流运行到deflater中会导致内存飙升)。
那么,我们可能正在寻找JRE的zip库的问题吗?似乎认为这会是问题很疯狂,但我真的很无助。
如果我取相同的流并在另一个系统上运行它(即使运行相同的JRE-32位,Java 7u45),我们不会遇到问题。我已经完全卸载了JRE并重新安装了它,但行为没有任何改变。