简体   繁体   English

有没有办法转储堆栈跟踪而不在java中抛出异常?

[英]Is there a way to dump a stack trace without throwing an exception in java?

I am thinking of creating a debug tool for my Java application.我正在考虑为我的 Java 应用程序创建一个调试工具。

I am wondering if it is possible to get a stack trace, just like Exception.printStackTrace() but without actually throwing an exception?我想知道是否有可能获得堆栈跟踪,就像Exception.printStackTrace()但实际上没有抛出异常?

My goal is to, in any given method, dump a stack to see who the method caller is.我的目标是,在任何给定的方法中,转储堆栈以查看方法调用者是谁。

是的,只需使用

Thread.dumpStack()

您还可以尝试使用Thread.getAllStackTraces()获取所有活动线程的堆栈跟踪图。

If you want the trace for just the current thread (rather than all the threads in the system, as Ram's suggestion does), do:如果您只想跟踪当前线程(而不是系统中的所有线程,正如 Ram 的建议所做的那样),请执行以下操作:

Thread.currentThread(). Thread.currentThread()。 getStackTrace() getStackTrace()

To find the caller, do:要找到来电者,请执行以下操作:

private String getCallingMethodName() {
    StackTraceElement callingFrame = Thread.currentThread().getStackTrace()[4];
    return callingFrame.getMethodName();
}

And call that method from within the method that needs to know who its caller is.并从需要知道其调用者是谁的方法中调用该方法。 However, a word of warning: the index of the calling frame within the list could vary according to the JVM!但是,警告一句:列表中调用帧的索引可能会因 JVM 的不同而有所不同! It all depends on how many layers of calls there are within getStackTrace before you hit the point where the trace is generated.这完全取决于在到达生成跟踪点之前 getStackTrace 中有多少层调用。 A more robust solution would be to get the trace, and iterate over it looking for the frame for getCallingMethodName, then take two steps further up to find the true caller.更健壮的解决方案是获取跟踪,并对其进行迭代以查找 getCallingMethodName 的框架,然后再采取两个步骤以找到真正的调用者。

You can get a stack trace like this:您可以获得这样的堆栈跟踪:

Throwable t = new Throwable();
t.printStackTrace();

If you want to access the frame, you can use t.getStackTrace() to get an array of stack frames.如果要访问帧,可以使用 t.getStackTrace() 获取堆栈帧数组。

Be aware that this stacktrace (just like any other) may be missing some frames if the hotspot compiler has been busy optimizing things.请注意,如果热点编译器一直忙于优化事物,则此堆栈跟踪(与任何其他跟踪一样)可能会丢失一些帧。

注意 Thread.dumpStack() 实际上抛出了一个异常:

new Exception("Stack trace").printStackTrace();

Java 9 introduced the StackWalker and supporting classes for walking the stack. Java 9 引入了StackWalker和用于遍历堆栈的支持类。

Here are a few snippets from the Javadoc:以下是 Javadoc 中的一些片段:

The walk method opens a sequential stream of StackFrames for the current thread and then applies the given function to walk the StackFrame stream. walk方法为当前线程打开一个StackFrames的顺序流,然后应用给定的函数来遍历StackFrame流。 The stream reports stack frame elements in order, from the top most frame that represents the execution point at which the stack was generated to the bottom most frame.流按顺序报告堆栈帧元素,从表示生成堆栈的执行点的最顶部帧到最底部帧。 The StackFrame stream is closed when the walk method returns.当 walk 方法返回时, StackFrame流将关闭。 If an attempt is made to reuse the closed stream, IllegalStateException will be thrown.如果尝试重用关闭的流,则会抛出IllegalStateException

... ...

  1. To snapshot the top 10 stack frames of the current thread,要对当前线程的前 10 个堆栈帧进行快照,

     List<StackFrame> stack = StackWalker.getInstance().walk(s -> s.limit(10).collect(Collectors.toList()));

You can also send a signal to the JVM to execute Thread.getAllStackTraces() on a running Java process by sending a QUIT signal to the process.您还可以通过向正在运行的 Java 进程发送 QUIT 信号,向 JVM 发送信号以在该进程上执行 Thread.getAllStackTraces()。

On Unix/Linux use:在 Unix/Linux 上使用:

kill -QUIT process_id , where process_id is the process number of your Java program. kill -QUIT process_id ,其中 process_id 是 Java 程序的进程号。

On Windows, you can press Ctrl-Break in the application, although you usually won't see this unless you're running a console process.在 Windows 上,您可以在应用程序中按 Ctrl-Break,尽管您通常不会看到这一点,除非您正在运行控制台进程。

JDK6 introduced another option, the jstack command, which will display the stack from any running JDK6 process on your computer: JDK6 引入了另一个选项,即 jstack 命令,它将显示您计算机上任何正在运行的 JDK6 进程的堆栈:

jstack [-l] <pid>

These options are very useful for applications which are running in a production environment and cannot be modified easily.这些选项对于在生产环境中运行且无法轻松修改的应用程序非常有用。 They're especially useful for diagnosing runtime deadlocks or performance problems.它们对于诊断运行时死锁或性能问题特别有用。

http://java.sun.com/developer/technicalArticles/Programming/Stacktrace/ http://java.sun.com/javase/6/docs/technotes/tools/share/jstack.html http://java.sun.com/developer/technicalArticles/Programming/Stacktrace/ http://java.sun.com/javase/6/docs/technotes/tools/share/jstack.html

If you need capture output如果您需要捕获输出

StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();

The answer by Rob Di Marco is by far the best if you are happy to output to stderr .如果您愿意输出到stderr那么Rob Di Marco答案是迄今为止最好的。

If you want to capture to a String , with new lines as per a normal trace, you could do this:如果您想捕获到String ,按照正常跟踪使用新行,您可以这样做:

Arrays.toString(Thread.currentThread().getStackTrace()).replace( ',', '\n' );

HPROF Java Profiler HPROF Java 分析器

You don't even have to do this in the code.您甚至不必在代码中执行此操作。 You can attach the Java HPROF to your process and at any point hit Control-\\ to output heap dump, running threads, etc .您可以将 Java HPROF 附加到您的进程,并随时点击 Control-\\ 以输出堆转储、正在运行的线程等。 . . . . without mucking up your application code.无需弄乱您的应用程序代码。 This is a bit outdated, Java 6 comes with the GUI jconsole, but I still find HPROF to be very useful.这有点过时了,Java 6 带有 GUI jconsole,但我仍然发现 HPROF 非常有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM