2010-05-07 34 views
11
  • 没有Java 6中,除了堆转储(java_pid14941.hprof)如何在生成线程转储Java的内存不足的错误

  • 这是发生了什么事我的应用程序之一生成线程转储。

    java.lang.OutOfMemoryError:GC开销超过限制 倾销堆java_pid14941.hprof ...

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

  • 是否有任何配置选项会在内存不足异常时除堆转储外还会生成线程转储?

回答

14

How to generate thread dump java on out of memory error?

你的问题可以简化为:

  • 如何生成线程转储

和:

  • 如何捕获内存不足的错误(唐在这里不注意反对者,他们错过了更大的图片,看我的评论)

所以它其实很简单,你可以做这样的:

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

  • ,检查是否有一个OutOfMemoryError

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

奖励:它在1上正常工作。5太:)

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

你可能想看看这个:

e.getMessage(); 

这:

Thread.getAllStackTraces(); 

我做这一切的时候在附带的应用程序数百个不同的1.5和1.6 JVM(在不同的操作系统上)。

+5

请注意,无知的评论者/反对者可能会想出像*“你永远不会捕捉OOM”这样的无意义,但他们可能从来没有在数百个系统上部署的Real-World TM Java应用程序上工作过。我一直这样做**和**它只是起作用**。这使我能够远程调试和修复很多非常微妙的内存泄漏,这在测试过程中从未出现过。在这里捕捉一个OOM是非常有意义的**,因为整个观点是要理解为什么OOM正在发生**。但不要惊讶,看到很多反对者在这里不理解这个非常基本的事实**。 – SyntaxT3rr0r 2010-05-07 12:18:01

+0

基于这个答案,我创建了实用工具类UncaughtExceptionLogger(http://pastebin.com/e30g9y66)。这个你可以定义为Spring bean,并且你都设置了扩展日志记录。 – snowindy 2014-12-17 04:37:36

0

我不认为在java中有什么东西可以为您提供退出线程转储。我在必要时通过定期执行kill -3 pid的cronjob来解决此问题。是的,它确实使日志杂乱一点,但占用空间仍然可以忽略不计。

如果您患有OOM,那么看看情况是如何演变为线程式的可能是有益的。

+0

为什么downvote? – mindas 2010-05-08 10:32:29

20

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

-XX:OnOutOfMemoryError="kill -3 pid" 

这样你就不必让应用程序产生周期性的线程转储,你会得到一个快照,当它实际上是窒息。

+5

事实上,事实证明,您可以将在OOME上生成的Heap Dump加载到VisualVM中,然后单击“堆转储中的线程”部分标题下的“显示线程”链接。 – 2010-05-25 17:48:48

+7

'-XX:OnOutOfMemoryError =“kill -3%p”' - 你不需要手动解析和指定pid(https://forums.oracle.com/forums/thread.jspa?threadID=2374398&tstart= 60) – yetanothercoder 2013-02-27 13:49:30

2

当使用jstack触发OnOutOfMemoryError时,可能触发线程转储。例如: -

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

基于接受的答案,我创建了工具类。这个你可以定义为一个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(); 
    } 
}