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

  • 除了堆转储之外java 6还生成线程转储(java_pid14941.hprof)

  • 这是我的一个应用程序发生的事情。

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

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

  • 是否有任何配置选项除了内存exception外的堆转储外还会产生线程转储?

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

您的问题可以简化为:

  • 如何生成线程转储

和:

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

所以它实际上非常简单,你可以这样做:

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

  • 捕获未捕获的exception时,检查是否有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(在不同的操作系统上)上提供。

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

 -XX:OnOutOfMemoryError="kill -3 pid" 

这样您就不必让应用程序生成定期的线程转储,并且当它实际窒息时您将获得快照。

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

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

我认为java中没有任何东西可以为您提供退出时的线程转储。 我必要时通过一个定期kill -3 pid的cronjob来解决这个问题。 是的,它确实使日志混乱,但足迹仍然可以忽略不计。

如果您患有OOM,那么了解情况是如何逐渐发展的可能是有益的。

基于接受的答案,我创建了实用程序类。 您可以将此定义为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 allThreads = Thread.getAllStackTraces(); Iterator 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(); } } 

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

遗憾地采用线程转储的JVM参数不起作用。 子进程无法结束SIGQUIT到父进程。

Oracle有-XX:CrashOnOutOfMemoryError但这在Java 8上可用。