除了堆转储(java_pid14941.hprof)之外java 6还生成线程转储
这是我的一个应用程序发生的事情。
java.lang.OutOfMemoryError:超出了GC开销限制 将堆转储到java_pid14941.hprof ...
我确实在工作目录中找到了ava_pid14941.hprof,但没有找到任何包含线程转储的文件。当我收到OutOfMemory错误时,我需要知道所有线程正在做什么。
除内存异常外的堆转储外,是否有任何配置选项会生成线程转储?
答案 0 :(得分:20)
如果你在Linux / Unix环境中,你可以这样做:
-XX:OnOutOfMemoryError="kill -3 pid"
通过这种方式,您不必让应用程序生成定期的线程转储,并且当它实际窒息时您将获得快照。
答案 1 :(得分:14)
如何生成线程转储java 内存不足错误?
您的问题可以简化为:
和
所以它实际上非常简单,你可以这样做:
安装默认的未捕获异常处理程序
捕获未捕获的异常后,检查是否有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(在不同的操作系统上)上提供的应用程序中一直这样做。
答案 2 :(得分:2)
使用jstack触发OnOutOfMemoryError时,可以触发线程转储。 e.g: -
jstack -F pid > /var/tmp/<identifier>.dump
答案 3 :(得分:0)
我认为java中没有任何东西可以为您提供退出时的线程转储。我在必要时通过定期kill -3 pid
的cronjob解决这个问题。是的,它会使日志混乱,但足迹仍然可以忽略不计。
如果您患有OOM,那么了解情况是如何逐渐发展的可能是有益的。
答案 4 :(得分: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();
}
}
答案 5 :(得分:0)
-XX:OnOutOfMemoryError="kill -3 %p"
使用线程转储的JVM参数可能无法正常工作。 子进程不能将SIGQUIT结束为父进程。
Oracle有-XX:CrashOnOutOfMemoryError
,但这可以在Java 8上找到。