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

如何在内存不足错误时生成线程转储java,java,crash-dumps,jvm-crash,Java,Crash Dumps,Jvm Crash,除了堆转储(java_pid14941.hprof)之外,Java6是否生成线程转储 这就是我的一个应用程序发生的情况 java.lang.OutOfMemoryError:超出GC开销限制 正在将堆转储到java_pid14941.hprof 我确实在工作目录中找到了ava_pid14941.hprof,但没有找到任何包含线程转储的文件。我需要知道当我得到这个OutOfMemory错误时所有线程都在做什么 除了内存不足异常时的堆转储之外,是否有任何配置选项将生成线程转储 我认为java中没有任

除了堆转储(java_pid14941.hprof)之外,Java6是否生成线程转储

  • 这就是我的一个应用程序发生的情况

    java.lang.OutOfMemoryError:超出GC开销限制 正在将堆转储到java_pid14941.hprof

  • 我确实在工作目录中找到了ava_pid14941.hprof,但没有找到任何包含线程转储的文件。我需要知道当我得到这个OutOfMemory错误时所有线程都在做什么

  • 除了内存不足异常时的堆转储之外,是否有任何配置选项将生成线程转储


  • 我认为java中没有任何东西可以为您提供退出时线程转储。在必要时,我会使用一个cronjob来处理这个问题,它会定期执行
    kill-3pid
    。是的,它确实使日志有点杂乱,但占用的空间仍然可以忽略不计

    如果你正遭受OOM的折磨,看看这种情况是如何发展的可能是有益的

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

    你的问题可以简化为:

    • 如何生成线程转储
    以及:

    • 如何捕捉内存不足错误(不要注意这里的反对者,他们忽略了大局,请参阅我的评论)
    所以这其实很简单,你可以这样做:

    • 安装默认的未捕获异常处理程序

    • 捕获未捕获的异常后,检查是否存在OutOfMemoryError

    • 如果您有OutOfMemoryError,请生成一个完整的线程转储,并要求用户通过电子邮件将其发送给您,或提供自动发送

    奖励:它在1.5版本也可以正常工作:)

    您可能希望了解以下内容:

     e.getMessage();
    
    这是:

    Thread.getAllStackTraces();
    

    我在一个应用程序中一直在这样做,该应用程序在数百种不同的1.5和1.6 JVM(在不同的操作系统上)上提供。

    如果您在Linux/Unix环境中,您可以这样做:

    -XX:OnOutOfMemoryError="kill -3 %p"
    
    这样,您就不必让应用程序定期生成线程转储,当它实际阻塞时,您将得到一个快照


    使用
    %p
    ,您不需要通过PID,JVM将自动选择正确的进程id作为。

    当使用jstack触发OnAutofMemoryError时,可以触发线程转储。e、 g:-

    jstack -F pid > /var/tmp/<identifier>.dump
    
    jstack-F pid>/var/tmp/.dump
    
    基于我创建的实用程序类的公认答案。这一个可以定义为Springbean,您可以使用扩展日志记录

    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();
        }
    }
    
    import java.util.Iterator;
    导入java.util.Map;
    导入javax.annotation.PostConstruct;
    导入org.apache.commons.lang3.exception.ExceptionUtils;
    导入org.slf4j.Logger;
    导入org.slf4j.LoggerFactory;
    公共类未捕获例外记录程序{
    私有最终静态记录器Logger=LoggerFactory.getLogger(UncaughtExceptionLogger.class);
    @施工后
    私有void init(){
    setDefaultUncaughtExceptionHandler(新的Thread.UncaughtExceptionHandler(){
    公共无效未捕获异常(最终线程t、最终可丢弃线程e){
    字符串msg=ExceptionUtils.getRootCauseMessage(e);
    logger.error(String.format(“未捕获异常处理程序捕获的表达式“%s”,msg)),e);
    if(msg.contains(“无法创建新的本机线程”)){
    字符串转储=CAPTURAREADDUMP();
    logger.error(String.format(
    “已为线程限制捕获OutOfMemoryError。线程转储:\n%s”,转储),e);
    }
    if(ExceptionUtils.getRootCause(e)instanceof OutOfMemoryError){
    字符串转储=CAPTURAREADDUMP();
    logger.error(String.format(“OutOfMemoryError已被捕获。线程转储:\n%s”,转储),e);
    }
    }
    });
    }
    公共静态字符串CAPTURATHREADDUMP(){
    /**
    * http://stackoverflow.com/questions/2787976/how-to-generate-thread-
    *内存不足时转储java错误
    * http://henryranch.net/software/capturing-a-thread-dump-in-java/
    */
    Map allThreads=Thread.getAllStackTraces();
    迭代器迭代器=allThreads.keySet().Iterator();
    StringBuffer StringBuffer=新的StringBuffer();
    while(iterator.hasNext()){
    线程键=(线程)迭代器.next();
    StackTraceeElement[]跟踪=(StackTraceeElement[])所有线程。获取(键);
    stringBuffer.append(键+“\r\n”);
    对于(int i=0;i
    -XX:onAutofmemoryError=“kill-3%p”

    获取线程转储的JVM参数不起作用。 子进程无法将SIGQUIT结束为父进程


    Oracle有
    -XX:CrashOnOutOfMemoryError
    ,但这在Java8上可用

    请注意,无知的评论者/反对者可能会提出一些毫无意义的建议,比如“你永远不应该听到OOM”,但他们可能从未在部署在数百个系统上的真实世界[TM]Java应用程序上工作过。我一直都这样做,而且很有效。这使我能够远程调试和修复许多在测试期间从未出现过的非常微妙的文件内存泄漏。在这里捕捉OOM是非常有意义的,因为关键是要理解OOM发生的原因。但是,看到这里有很多反对者不理解这一基本事实,不要感到惊讶。基于这个答案,我创建了实用程序类UncaughtExceptionLogger()。比如说,你可以将它定义为一个Springbean,并且你已经准备好了扩展日志记录。实际上,你可以将OOME上生成的堆转储加载到VisualVM中,然后点击“堆转储中的线程”一节下的“显示线程”链接
    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();
        }
    }