简体   繁体   English

如何在内存不足错误时生成线程转储 java

[英]how to generate thread dump java on out of memory error

  • does java 6 generate thread dump in addition to heap dump (java_pid14941.hprof)除了堆转储(java_pid14941.hprof)之外,java 6 是否还生成线程转储

  • this is what happened to one of my applications.这就是我的一个应用程序发生的情况。

    java.lang.OutOfMemoryError: GC overhead limit exceeded Dumping heap to java_pid14941.hprof ... java.lang.OutOfMemoryError: GC 开销限制超出 Dumping heap to java_pid14941.hprof ...

  • I did find ava_pid14941.hprof in working directory, but didn't find any file which contains thread dump.我确实在工作目录中找到了 ava_pid14941.hprof,但没有找到任何包含线程转储的文件。 I need to know what all the threads were doing when I got this OutOfMemory error.当我收到 OutOfMemory 错误时,我需要知道所有线程在做什么。

  • Is there any configuration option which will generate thread dump in addition to heap dump on out of memory exception?除了内存不足异常的堆转储之外,是否有任何配置选项会生成线程转储?

If you're in a Linux/Unix environment you can do this:如果你在 Linux/Unix 环境中,你可以这样做:

-XX:OnOutOfMemoryError="kill -3 %p"

This way you don't have to have your application generate periodic thread dumps and you'll get a snapshot when it actually chokes.这样你就不必让你的应用程序生成周期性的线程转储,当它实际阻塞时你会得到一个快照。

With %p , you don't need to pass the PID, JVM will automatically pick the correct process id as mentioned here .使用%p ,您无需传递 PID,JVM 将自动选择此处提到的正确进程 ID。

How to generate thread dump java on out of memory error?如何在内存不足错误时生成线程转储 java?

Your question can be simplified into:你的问题可以简化为:

  • how to generate a thread dump如何生成线程转储

and:和:

  • how to catch an out of memory error (don't pay attention to naysayer here, they're missing the bigger picture, see my comment)如何捕捉内存不足错误(不要在这里注意反对者,他们错过了更大的图景,请参阅我的评论)

So it's actually quite easy, you could do it like this:所以它实际上很容易,你可以这样做:

  • install a default uncaught exception handler安装默认的未捕获异常处理程序

  • upon catching an uncaught exception, check if you have an OutOfMemoryError捕获未捕获的异常后,检查您是否有 OutOfMemoryError

  • if you have an OutOfMemoryError, generate yourself a full thread dump and either ask the user to send it to you by email or offer to send it automatically如果您有 OutOfMemoryError,请为自己生成一个完整的线程转储,并要求用户通过电子邮件将其发送给您,或者提供自动发送

Bonus: it works fine on 1.5 too :)奖励:它在 1.5 上也能正常工作:)

 Thread.setDefaultUncaughtExceptionHandler( new Thread.UncaughtExceptionHandler() {
     public void uncaughtException( final Thread t, final Throwable e ) {
         ...
     }

You may want to look into this:你可能想看看这个:

 e.getMessage();

and this:和这个:

Thread.getAllStackTraces();

I'm doing this all the time in an app that is shipped on hundreds of different 1.5 and 1.6 JVM (on different OSes).我一直在一个应用程序中这样做,该应用程序在数百个不同的 1.5 和 1.6 JVM(在不同的操作系统上)上提供。

It's possible to trigger a thread dump when OnOutOfMemoryError is triggered using jstack.当使用 jstack 触发 OnOutOfMemoryError 时,可以触发线程转储。 eg:-例如:-

jstack -F pid > /var/tmp/<identifier>.dump

-XX:OnOutOfMemoryError="kill -3 %p"

The JVM argument to take thread dump sadly don't work.可悲的是,JVM 参数进行线程转储不起作用。 Child process cannot end SIGQUIT to parent.子进程不能结束对父进程的 SIGQUIT。

Oracle has -XX:CrashOnOutOfMemoryError but this is available on Java 8. Oracle 有-XX:CrashOnOutOfMemoryError但这在 Java 8 上可用。

Based on the accepted answer I created utility class.基于接受的答案,我创建了实用程序类。 This one you can define as a Spring bean and you're all set with extended logging.您可以将这个定义为 Spring bean,并且您都设置了扩展日志记录。

import java.util.Iterator;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UncaughtExceptionLogger {

    private final static Logger logger = LoggerFactory.getLogger(UncaughtExceptionLogger.class);

    @PostConstruct
    private void init() {
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            public void uncaughtException(final Thread t, final Throwable e) {
                String msg = ExceptionUtils.getRootCauseMessage(e);
                logger.error(String.format("Uncaght exception handler captured expcetion '%s'", msg), e);
                if (msg.contains("unable to create new native thread")) {
                    String dump = captureThreadDump();
                    logger.error(String.format(
                            "OutOfMemoryError has been captured for threads limit. Thread dump: \n %s", dump), e);
                }
                if (ExceptionUtils.getRootCause(e) instanceof OutOfMemoryError) {
                    String dump = captureThreadDump();
                    logger.error(String.format("OutOfMemoryError has been captured. Thread dump: \n %s", dump), e);
                }
            }
        });
    }

    public static String captureThreadDump() {
        /**
         * http://stackoverflow.com/questions/2787976/how-to-generate-thread-
         * dump-java-on-out-of-memory-error
         * http://henryranch.net/software/capturing-a-thread-dump-in-java/
         */
        Map<Thread, StackTraceElement[]> allThreads = Thread.getAllStackTraces();
        Iterator<Thread> iterator = allThreads.keySet().iterator();
        StringBuffer stringBuffer = new StringBuffer();
        while (iterator.hasNext()) {
            Thread key = (Thread) iterator.next();
            StackTraceElement[] trace = (StackTraceElement[]) allThreads.get(key);
            stringBuffer.append(key + "\r\n");
            for (int i = 0; i < trace.length; i++) {
                stringBuffer.append(" " + trace[i] + "\r\n");
            }
            stringBuffer.append("");
        }
        return stringBuffer.toString();
    }
}

I don't think there is anything in java that would provide you with on-exit thread dumps.我认为 Java 中没有任何东西可以为您提供退出时的线程转储。 I tackle this when necessary by having a cronjob that does periodic kill -3 pid .我在必要时通过定期执行kill -3 pid的 cronjob 来解决这个问题。 Yes, it does clutter the logs a bit, but the footprint is still negligible.是的,它确实使日志有点混乱,但足迹仍然可以忽略不计。

And if you are suffering from OOM, it might be be beneficial to see how the situation evolved thread-wise.如果您正遭受 OOM 的困扰,那么了解情况如何逐线演变可能会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM