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

发布于 2024-09-01 04:37:10 字数 318 浏览 7 评论 0原文

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

  • ?应用程序。

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

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

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

  • does java 6 generate thread dump in addition to heap dump (java_pid14941.hprof)

  • this is what happened to one of my applications.

    java.lang.OutOfMemoryError: GC overhead limit exceeded
    Dumping heap to java_pid14941.hprof ...

  • I did find ava_pid14941.hprof in working directory, but didn't find any file which contains thread dump. I need to know what all the threads were doing when I got this OutOfMemory error.

  • Is there any configuration option which will generate thread dump in addition to heap dump on out of memory exception?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

攒一口袋星星 2024-09-08 04:37:11

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

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

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

使用%p,您不需要传递PID,JVM会自动选择正确的进程ID作为这里提到

If you're in a Linux/Unix environment you can do this:

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

This way you don't have to have your application generate periodic thread dumps and you'll get a snapshot when it actually chokes.

With %p, you don't need to pass the PID, JVM will automatically pick the correct process id as mentioned here.

人事已非 2024-09-08 04:37:11

如何在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(不同操作系统)上运行的应用程序中始终存在这种情况。

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

Your question can be simplified into:

  • how to generate a thread dump

and:

  • how to catch an out of memory error (don't pay attention to naysayer here, they're missing the bigger picture, see my comment)

So it's actually quite easy, you could do it like this:

  • install a default uncaught exception handler

  • upon catching an uncaught exception, check if you have an OutOfMemoryError

  • if you have an OutOfMemoryError, generate yourself a full thread dump and either ask the user to send it to you by email or offer to send it automatically

Bonus: it works fine on 1.5 too :)

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

You may want to look into this:

 e.getMessage();

and this:

Thread.getAllStackTraces();

I'm doing this all the time in an app that is shipped on hundreds of different 1.5 and 1.6 JVM (on different OSes).

守望孤独 2024-09-08 04:37:11

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

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

It's possible to trigger a thread dump when OnOutOfMemoryError is triggered using jstack. e.g:-

jstack -F pid > /var/tmp/<identifier>.dump
莫言歌 2024-09-08 04:37:11

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

如果您正遭受 OOM 的困扰,那么了解情况如何按线程演变可能会有所帮助。

I don't think there is anything in java that would provide you with on-exit thread dumps. I tackle this when necessary by having a cronjob that does periodic kill -3 pid. Yes, it does clutter the logs a bit, but the footprint is still negligible.

And if you are suffering from OOM, it might be be beneficial to see how the situation evolved thread-wise.

半世蒼涼 2024-09-08 04:37:11

根据接受的答案,我创建了实用程序类。您可以将其定义为 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();
    }
}

Based on the accepted answer I created utility class. This one you can define as a Spring bean and you're all set with extended logging.

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();
    }
}
慢慢从新开始 2024-09-08 04:37:11

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

遗憾的是,用于进行线程转储的 JVM 参数不起作用。
子进程无法结束对父进程的 SIGQUIT。

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

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

The JVM argument to take thread dump sadly don't work.
Child process cannot end SIGQUIT to parent.

Oracle has -XX:CrashOnOutOfMemoryError but this is available on Java 8.

俏︾媚 2024-09-08 04:37:11

假设您的目标服务器上安装了 JDK(不是 JRE),您可以依靠命令 jcmd 来生成线程转储,这样无论服务器的操作系统如何,它都可以工作。

定义在 OutOfMemoryError 上执行的命令的 JVM 选项如下:

-XX:OnOutOfMemoryError="jcmd %p Thread.print"

其中 %p 指定当前进程 ID

此外,由于我们可能希望将线程转储到文件中,可以通过添加 JVM 选项 -XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=jvm.log 将其放入 JVM 日志文件中,这样堆转储就可用位于 JVM 工作目录中的文件 jvm.log 中,以及用于诊断 JVM 的其他信息。

要添加的 JVM 选项的完整列表如下:

-XX:OnOutOfMemoryError="jcmd %p Thread.print" -XX:+UnlockDiagnosticVMOptions
-XX:+LogVMOutput -XX:LogFile=jvm.log

请注意,即使没有发生 OOME,文件也始终会创建,因此在服务器上,如果您想避免在下次启动时替换先前的 JVM 文件,您应该考虑在日志文件的名称中添加进程 ID,例如 jvm_pid%p.log,但不要忘记定期删除文件。

如果未设置 JVM 选项 -XX:LogFile,则默认情况下文件名的类型为 hotspot_pid%p.log,其中 %p 指定当前进程ID。


实际上,唯一需要的 JVM 选项是 -XX:+HeapDumpOnOutOfMemoryError,因为它允许在发生 OnOutOfMemoryError 时生成 hprof 文件。已经包含线程转储。

请参阅下面如何使用 VisualVMhprof 文件获取线程转储:

< a href="https://i.sstatic.net/UkiZw.gif" rel="nofollow noreferrer">获取线程转储来自 hprof

Assuming that you have a JDK (not a JRE) installed on your target server, you can rely on the command jcmd to generate your thread dump, this way it will work whatever the OS of your server.

The JVM option defining the command to execute on OutOfMemoryError is then:

-XX:OnOutOfMemoryError="jcmd %p Thread.print"

Where %p designates the current process id

Moreover, as we could want to have the thread dump into a file, it is possible to have it into the JVM log file by adding the JVM options -XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=jvm.log, this way the heap dump will be available in the file jvm.log located in the working directory of the JVM along with other information intended for diagnosing the JVM.

The full list of JVM options to add is then:

-XX:OnOutOfMemoryError="jcmd %p Thread.print" -XX:+UnlockDiagnosticVMOptions
-XX:+LogVMOutput -XX:LogFile=jvm.log

Be aware that the file is always created even when no OOME happens, so on a server, if you want to avoid having the previous JVM file being replaced at the next startup, you should consider adding the process id in the name of the log file like for example jvm_pid%p.log but don't forget to remove the files regularly.

If the JVM option -XX:LogFile is not set, by default the name of the file is of type hotspot_pid%p.log where %p designates the current process id.


In practice, the only JVM option that is needed is -XX:+HeapDumpOnOutOfMemoryError as it allows to generate an hprof file when an OnOutOfMemoryError occurs which already contains a thread dump.

See below how to get a thread dump from an hprof file using VisualVM:

Get Thread Dump from hprof

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文