我们最近得到一个OutOfMemory是由于“无法在我们的Tomcat服务器上创建新的本机线程”。我们知道问题是什么 - 有一个错误产生了太多的线程,超出了盒子上允许的ulimit。
引起我兴趣的是,当发生这种情况时,JVM没有转储堆。我检查了Java 6和8中的行为是否一致。
我写了一些快速的Groovy PoC来证明这种行为。因此,虽然我在这里使用了groovy,但行为与我的Servlet应用程序一致(我更容易分享问题的工作模型)。
转储堆 - TraditionalOOM.groovy
:
byte[] b = new byte[1000000000]
NOT 转储堆 - ManyThreads.groovy
:
int MAX = 5000;
for (int i = 0; i < MAX; i++) {
new Thread() {
public void run() {
sleep(1000);
}
}.start();
}
Thread.activeCount();
与此问题相关的Java选项(IMHO)如下2所示:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/somewhere
我想知道:
更新
我得到了答案 - 似乎这是预期的行为,而Oracle(或Sun)已将此行为视为缺陷 - http://bugs.java.com/bugdatabase/view_bug.do;jsessionid=74ee28dae329645479a51f6c78f2?bug_id=6784422
答案 0 :(得分:0)
我得到了我的答案 - 看起来这是预期的行为,Oracle(或Sun)拒绝将此行为视为缺陷 -
http://bugs.java.com/bugdatabase/view_bug.do;jsessionid=74ee28dae329645479a51f6c78f2?bug_id=6784422
链接状态&#34;本机线程的分配不是来自堆或永久生成 - 因此无法分配一个不会导致堆转储。 (倾销堆没有什么意义,因为那不是用尽的。)&#34;
我并不完全同意,因为堆转储在线程上也有大量信息。如果那是Oracle的(或者太阳的)位置,JVM至少应该转储线程转储。