OutOfMemory导致“无法创建新的本机线程”时堆转储

时间:2015-12-08 00:13:19

标签: java multithreading jvm out-of-memory heap-dump

我们最近得到一个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

我想知道:

  • 为什么JVM在OOM期间不会转储堆(甚至转储线程转储会有帮助)?
  • 答案显而易见,JVM没有执行转储的线程吗?

更新

我得到了答案 - 似乎这是预期的行为,而Oracle(或Sun)已将此行为视为缺陷 - http://bugs.java.com/bugdatabase/view_bug.do;jsessionid=74ee28dae329645479a51f6c78f2?bug_id=6784422

1 个答案:

答案 0 :(得分:0)

我得到了我的答案 - 看起来这是预期的行为,Oracle(或Sun)拒绝将此行为视为缺陷 -

http://bugs.java.com/bugdatabase/view_bug.do;jsessionid=74ee28dae329645479a51f6c78f2?bug_id=6784422

链接状态&#34;本机线程的分配不是来自堆或永久生成 - 因此无法分配一个不会导致堆转储。 (倾销堆没有什么意义,因为那不是用尽的。)&#34;

我并不完全同意,因为堆转储在线程上也有大量信息。如果那是Oracle的(或者太阳的)位置,JVM至少应该转储线程转储。