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

cor*_*ath 145 java debugging logging exception stack-trace

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

我想知道是否有可能获得堆栈跟踪,就像Exception.printStackTrace()没有实际抛出异常一样?

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

Rob*_*rco 229

是的,只需使用

Thread.dumpStack()
Run Code Online (Sandbox Code Playgroud)

  • ......但不抛弃它. (42认同)
  • 非常简单而优雅.这应该是公认的答案. (6认同)
  • 首先,此方法的来源:`public static void dumpStack(){new Exception(“ Stack trace”)。printStackTrace(); }` (6认同)
  • 这就是实际解决问题的答案. (4认同)

Pra*_*u R 81

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

  • +1,如果他想分析堆栈跟踪肯定有用! (4认同)

Tom*_*son 40

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

Thread.currentThread().的getStackTrace()

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

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

并从需要知道其调用者是谁的方法中调用该方法.但是,请注意:列表中调用帧的索引可能因JVM而异!这一切都取决于在生成跟踪之前getStackTrace中有多少层调用.一个更强大的解决方案是获取跟踪,并迭代它以查找getCallingMethodName的帧,然后进一步向上找两个真正的调用者.

  • 所以只需自己创建一个新的异常并使用 [1] 作为索引! (2认同)
  • 这个问题的标题是"没有抛出异常".当然,你建议创建例外但不抛弃它,但我仍然认为这不符合问题的精神. (2认同)

Ger*_*ies 34

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

Throwable t = new Throwable();
t.printStackTrace();
Run Code Online (Sandbox Code Playgroud)

如果要访问该帧,可以使用t.getStackTrace()来获取堆栈帧数组.

请注意,如果热点编译器忙于优化,那么这个堆栈跟踪(就像其他任何一样)可能会丢失一些帧.

  • 在一行中:`new Throwable().printStackTrace(System.out);` (4认同)
  • 并且很容易发送到 java.util.Logger `log.log(Level.SEVERE, "Failed to do something", new Throwable());` (4认同)

Ari*_*l T 13

请注意,Thread.dumpStack()实际上会抛出异常:

new Exception("Stack trace").printStackTrace();
Run Code Online (Sandbox Code Playgroud)

  • 它会创建一个异常,但不会抛出异常. (11认同)

mko*_*bit 9

Java 9 引入了StackWalker用于遍历堆栈的类和支持类。

以下是 Javadoc 中的一些片段:

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

...

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

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


mik*_*ent 8

如果您乐意输出到 ,那么Rob Di Marco 的答案是迄今为止最好的stderr

String如果您想按照正常跟踪捕获到新行,您可以这样做:

Arrays.toString(Thread.currentThread().getStackTrace()).replace( ',', '\n' );
Run Code Online (Sandbox Code Playgroud)


Ric*_*ino 7

如果您需要捕获输出

StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
Run Code Online (Sandbox Code Playgroud)


And*_*ate 6

您还可以通过向进程发送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