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

问题描述 投票:0回答:10

我正在考虑为我的 Java 应用程序创建一个调试工具。

我想知道是否有可能获得堆栈跟踪,就像

Exception.printStackTrace()
但实际上没有抛出异常?

我的目标是,在任何给定的方法中,转储堆栈以查看方法调用者是谁。

java debugging exception logging stack-trace
10个回答
325
投票

是的,只需使用

Thread.dumpStack()

88
投票

您还可以尝试

Thread.getAllStackTraces()
获取所有活动线程的堆栈跟踪图。


58
投票

如果您只想跟踪当前线程(而不是像 Ram 的建议那样跟踪系统中的所有线程),请执行以下操作:

Thread.currentThread().getStackTrace()

要找到呼叫者,请执行以下操作:

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

并从需要知道其调用者是谁的方法中调用该方法。但是,请注意:列表中调用框架的索引可能会根据 JVM 的不同而有所不同!这完全取决于在到达生成跟踪的点之前 getStackTrace 中有多少层调用。更可靠的解决方案是获取跟踪,并迭代它以查找 getCallingMethodName 的框架,然后进一步向上两步找到真正的调用者。


43
投票

您可以获得这样的堆栈跟踪:

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

如果要访问帧,可以使用

t.getStackTrace()
获取堆栈帧数组。

请注意,如果热点编译器一直忙于优化事物,则此堆栈跟踪(就像任何其他堆栈跟踪一样)可能会丢失一些帧。


16
投票

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

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

12
投票

Java 9 引入了

StackWalker
以及用于遍历堆栈的支持类。

以下是 Javadoc 中的一些片段:

walk
方法为当前线程打开
StackFrames
的顺序流,然后应用给定的函数来遍历
StackFrame
流。该流按顺序报告堆栈帧元素,从表示生成堆栈的执行点的最顶部帧到最底部帧。当 walk 方法返回时,
StackFrame
流将关闭。如果尝试重用已关闭的流,则会抛出
IllegalStateException

...

  1. 要快照当前线程的前10个堆栈帧,

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

7
投票

您还可以通过向进程发送 QUIT 信号来向 JVM 发送信号,以在正在运行的 Java 进程上执行 Thread.getAllStackTraces()。

在 Unix/Linux 上使用:

kill -QUIT process_id
,其中process_id是您的Java程序的进程号。

在 Windows 上,您可以在应用程序中按 Ctrl-Break,但除非您正在运行控制台进程,否则您通常不会看到这一点。

JDK6 引入了另一个选项,即 jstack 命令,它将显示计算机上任何正在运行的 JDK6 进程的堆栈:

jstack [-l] <pid>

这些选项对于在生产环境中运行并且不能轻易修改的应用程序非常有用。它们对于诊断运行时死锁或性能问题特别有用。

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


7
投票

如果您需要捕获输出

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

7
投票
如果您乐意输出到

stderr,那么 Rob Di Marco

 答案是迄今为止最好的。 

如果您想捕获到

String

,并按照正常轨迹使用新行,您可以这样做:

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

0
投票

HPROF Java 分析器

您甚至不必在代码中执行此操作。您可以将 Java HPROF 附加到您的进程,并在任何时候点击 Control-\ 来输出堆转储、运行线程等。 。 。不会弄乱您的应用程序代码。这有点过时了,Java 6 附带了 GUI jconsole,但我仍然发现 HPROF 非常有用。

© www.soinside.com 2019 - 2024. All rights reserved.