【发布时间】:2010-10-31 00:11:02
【问题描述】:
我正在考虑为我的 Java 应用程序创建一个调试工具。
我想知道是否可以获得堆栈跟踪,就像Exception.printStackTrace() 但实际上没有抛出异常?
我的目标是,在任何给定的方法中,转储堆栈以查看方法调用者是谁。
【问题讨论】:
标签: java debugging exception logging stack-trace
我正在考虑为我的 Java 应用程序创建一个调试工具。
我想知道是否可以获得堆栈跟踪,就像Exception.printStackTrace() 但实际上没有抛出异常?
我的目标是,在任何给定的方法中,转储堆栈以查看方法调用者是谁。
【问题讨论】:
标签: java debugging exception logging stack-trace
是的,只需使用
Thread.dumpStack()
【讨论】:
public static void dumpStack() { new Exception("Stack trace").printStackTrace(); }
stderr 感到满意,这是迄今为止问题的最佳答案,这似乎是问题的含义。
您也可以尝试Thread.getAllStackTraces() 获取所有活动线程的堆栈跟踪图。
【讨论】:
如果您只想跟踪当前线程(而不是系统中的所有线程,如 Ram 的建议),请执行以下操作:
Thread.currentThread().getStackTrace()
要查找调用者,请执行以下操作:
private String getCallingMethodName() {
StackTraceElement callingFrame = Thread.currentThread().getStackTrace()[4];
return callingFrame.getMethodName();
}
然后从需要知道调用者是谁的方法中调用该方法。但是,请注意:列表中调用帧的索引可能会因 JVM 而异!这完全取决于在到达生成跟踪点之前 getStackTrace 中有多少层调用。一个更强大的解决方案是获取跟踪,并对其进行迭代以查找 getCallingMethodName 的框架,然后再往前走两步以找到真正的调用者。
【讨论】:
你可以获得这样的堆栈跟踪:
Throwable t = new Throwable();
t.printStackTrace();
如果要访问帧,可以使用 t.getStackTrace() 获取堆栈帧数组。
请注意,如果热点编译器一直忙于优化,此堆栈跟踪(就像任何其他堆栈跟踪一样)可能会丢失一些帧。
【讨论】:
t.printStackTrace(System.out) 替换t.printStackTrace。
new Throwable().printStackTrace(System.out);
log.log(Level.SEVERE, "Failed to do something", new Throwable());
注意 Thread.dumpStack() 实际上抛出了一个异常:
new Exception("Stack trace").printStackTrace();
【讨论】:
Java 9 引入了 StackWalker 和支持类来遍历堆栈。
这里有一些来自 Javadoc 的 sn-ps:
walk方法为当前线程打开StackFrames的顺序流,然后应用给定函数遍历StackFrame流。该流按顺序报告堆栈帧元素,从表示生成堆栈的执行点的最顶部帧到最底部帧。当 walk 方法返回时,StackFrame流将关闭。如果尝试重用关闭的流,IllegalStateException将被抛出。...
要快照当前线程的前 10 个堆栈帧,
List<StackFrame> stack = StackWalker.getInstance().walk(s -> s.limit(10).collect(Collectors.toList()));
【讨论】:
您还可以通过向进程发送 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
【讨论】:
如果你需要捕获输出
StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
【讨论】:
如果您愿意输出到stderr,answer by Rob Di Marco 是迄今为止最好的。
如果您想捕获到String,按照正常跟踪使用新行,您可以这样做:
Arrays.toString(Thread.currentThread().getStackTrace()).replace( ',', '\n' );
【讨论】:
您甚至不必在代码中执行此操作。您可以将 Java HPROF 附加到您的进程,并随时点击 Control-\ 以输出堆转储、正在运行的线程等。 . .无需破坏您的应用程序代码。这有点过时了,Java 6 自带了 GUI jconsole,但我还是觉得 HPROF 很有用。
【讨论】: