如何在内存错误中生成线程dump java
-
04-10-2019 - |
题
Java 6以外是否生成线程转储(Java_pid14941.hprof)
这就是我的一个应用程序之一。
java.lang.outofmemoryerror:GC间接费用限制超过将堆倾倒到java_pid14941.hprof ...
我确实在工作目录中找到了ava_pid14941.hprof,但没有找到任何包含线程转储的文件。我需要知道所有线程在遇到此余写错误时在做什么。
是否有任何配置选项除了在内存异常之外生成堆转储之外,还会生成线程转储吗?
解决方案
如何在内存错误中生成线程转储Java?
您的问题可以简化为:
- 如何生成线程转储
和:
- 如何捕捉到不记忆错误(不要注意反对者,他们缺少大图,请参阅我的评论)
因此,实际上很容易,您可以这样做:
安装一个默认未见的异常处理程序
捕获未被发现的例外,检查您是否有eutofMemoryError
如果您有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(在不同的OSS上)发货。
其他提示
如果您在Linux/Unix环境中,可以做到这一点:
-XX:OnOutOfMemoryError="kill -3 pid"
这样,您就不必让应用程序生成定期线程转储,并且在实际窒息时会获得快照。
当使用JSTACK触发OnOuTofMemoryError时,可以触发线程转储。例如:-
jstack -F pid > /var/tmp/<identifier>.dump
我认为Java中没有任何东西可以为您提供外部线程转储。我在必要时通过定期进行cronjob来解决这个问题 kill -3 pid
. 。是的,它确实会使日志有些混乱,但是足迹仍然可以忽略不计。
而且,如果您遭受OOM的困扰,那么看看情况如何发展线程可能是有益的。
基于我创建的公用事业课程的公认答案。您可以将其定义为弹簧豆,并且所有人都会设置为扩展日志记录。
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();
}
}
-XX:OnOutOfMemoryError="kill -3 %p"
JVM的争论可悲地将线程转储不起作用。儿童进程无法结束父母的sig词。
Oracle有 -XX:CrashOnOutOfMemoryError
但这可以在Java 8上找到。