我们最近收到的OutOfMemory是由于我们的Tomcat服务器上“无法创建新的本机线程”。我们知道问题出在哪里-有一个错误产生了一个错误,超出了包装盒上ulimit的允许范围。

令我着迷的是,发生这种情况时,JVM没有转储堆。我检查了Java 6和8中的行为是否一致。

我编写了一些快速的Groovy PoC来证明这种行为。因此,尽管我在这里使用了Groovy,但是其行为与Servlet应用程序一致(对于我来说,更容易共享问题的工作模型)。

转储堆-TraditionalOOM.groovy

byte[] b = new byte[1000000000]


不转储堆-ManyThreads.groovy

int MAX = 5000;

for (int i = 0; i < MAX; i++) {

    new Thread() {
        public void run() {
            sleep(1000);
        }
    }.start();
}

Thread.activeCount();


与该问题(IMHO)相关的Java选项如下:2:

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/somewhere


我想知道:


为什么JVM在OOM期间不转储堆(即使转储线程转储也会有所帮助)?
答案很明显吗,那就是JVM没有执行转储的线程?




更新资料

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

最佳答案

我得到了答案-似乎这是预期的行为,而Oracle(或Sun)拒绝了此行为作为缺陷-

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

链接指出:“分配本机线程不是来自堆或永久代,因此分配失败不会导致堆转储。(转储堆的意义不大,因为这并不是用尽的。 )”

我并不完全同意,因为堆转储在线程上也有很多信息。如果这是Oracle(或Sun)的位置,则JVM应该至少转储线程转储。

关于java - OutOfMemory由于“无法创建新的 native 线程”而导致的堆转储,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34145797/

10-11 20:43
查看更多