Kev*_*Day 15 java memory multithreading
我们有一个广泛部署的应用程序(运行它的几百个工作站).在一个站点(并且只有一个站点 - 我们的产品被广泛部署到许多环境中),我们随机出现以下错误:
java.lang.OutOfMemoryError:无法在java.lang.Thread.start(未知来源)的java.lang.Thread.start0(本机方法)中创建新的本机线程
操作系统是Windows 7 64位我们运行在32位JVM(1.7.0_45)
使用Windows任务管理器,我可以看到该进程有39个本机线程(不是很多),所以我们的应用程序中没有线程泄漏...没有其他进程占用大量线程(Explorer有35个, jvisualvm有24个,IEXPLORE有20个,...我没有确切的数目,但我们可能看也许 300线程的用户总数).
我试图附加JVisualVM,但它无法连接到进程(可能是线程耗尽的b/c).但是根据我可以从JVisualVM获得的指标,Java线程的数量约为22个实时和11个守护进程.
堆很好 - 堆是500MB,实际使用250MB.
该过程使用-Xmx512m启动
我们的流程显示内存使用情况(在任务管理器中)为597,744K.
工作站有8GB RAM,其中只使用3.8-4.0GB(我知道,32位进程无法访问所有这些,但仍然有很多)
使用的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崩溃了"无法创建新的本机线程" - 任何想法?(我的设置和信息)
他们建议堆栈大小可能是问题.
本文:在哪里可以找到Sun/Oracle JVM的默认XSS值? - 提供Oracle文档的链接,指出默认堆栈大小为512KB.因此,如果我的应用程序有大约40个线程,我们正在寻找20 MB的堆栈.500MB堆.这一切似乎都在32位Java进程的正常范围内.
这让我有两个可以想到的可能性:
那么,有没有关于如何检查内存分段的指针?
编辑2:
链接到@mikhael的文章(http://blog.egilh.com/2006/06/2811aspx.html)对32位JVM上允许的#个线程进行了粗略计算.
我要假设:
操作系统进程空间限制: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 ....
Run Code Online (Sandbox Code Playgroud)
在一些非常小的流(我现在有4个例子)我们正在收缩,上面发生了.当它发生时,VMMap将进程堆(而不是JVM堆,但实际的本机堆)高达2GB.一旦发生这种情况,一切都会崩溃.这现在是非常可重复的(在deflater中运行相同的流导致内存尖峰)
那么,我们是否可能会看到JRE的zip库存在问题?看起来很疯狂,但我真的很茫然.
如果我采用完全相同的流并在不同的系统上运行它(甚至运行相同的JRE - 32位,Java 7u45),我们就不会遇到问题.我已经完全卸载了JRE并重新安装它而没有任何行为改变.
终于明白了这一点。
我们处理了几个数据流(此站点的 1000 万个数据流中有 4 个)最终创建了大量的 DeflaterOutputStream 对象。我们使用的第三方库在流上调用 finish() 而不是 close()。底层的 Deflater 终结器正在清理一切,因此只要负载不太高,就不会有问题。但过了一个临界点,我们开始遇到这个问题:
http://jira.pentaho.com/browse/PRD-3211
这导致我们这样做:
https://bugs.java.com/bugdatabase/view_bug?bug_id=4797189
发生这种情况几个小时后,系统终于陷入了无法摆脱的困境,无法在我们需要时创建本机线程。
修复方法是让第 3 方库关闭 DeflaterOutputStream。
所以绝对是本机资源泄漏。如果其他人遇到过类似的问题,VMMap 工具对于最终追踪导致问题的数据流是必不可少的。
| 归档时间: |
|
| 查看次数: |
9771 次 |
| 最近记录: |