我正在考虑为我的Java应用程序创建一个调试工具。有没有办法转储堆栈跟踪,而不会在java中引发异常?
我想知道是否有可能获得堆栈跟踪,就像Exception.printStackTrace()
,但实际上并没有抛出异常?
我的目标是,在任何给定的方法中,转储堆栈以查看方法调用者是谁。
我正在考虑为我的Java应用程序创建一个调试工具。有没有办法转储堆栈跟踪,而不会在java中引发异常?
我想知道是否有可能获得堆栈跟踪,就像Exception.printStackTrace()
,但实际上并没有抛出异常?
我的目标是,在任何给定的方法中,转储堆栈以查看方法调用者是谁。
您也可以尝试Thread.getAllStackTraces()
拿到地图的堆栈跟踪的所有还活着的线程。
你可以得到一个堆栈跟踪这样的:
Throwable t = new Throwable();
t.printStackTrace();
如果您要访问的框架,你可以使用t.getStackTrace()得到一个堆栈帧数组。
请注意,如果热点编译器一直在忙于优化事情,则此堆栈跟其他任何可能会丢失一些帧。
我喜欢这个答案,因为它为我提供了指导输出的机会。我可以用`t.printStackTrace(System.out)`替换`t.printStackTrace`。 – 2015-10-31 23:21:18
如果你想为只是当前线程的跟踪(而不是所有的线程在Ram的建议中):
Thread.currentThread()。 getStackTrace()
要找到来电者,这样做:
private String getCallingMethodName() {
StackTraceElement callingFrame = Thread.currentThread().getStackTrace()[4];
return callingFrame.getMethodName();
}
,并调用该方法从需要知道它的调用者是谁的方法中。但是,警告一句话:列表中调用框架的索引可能因JVM而异!这完全取决于getStackTrace中有多少层调用,然后才能生成跟踪点。更强大的解决方案是获取跟踪,并遍历它寻找getCallingMethodName的框架,然后再进一步查找真正的调用者。
您甚至不必这样做的代码。您可以将Java HPROF附加到您的进程,并在任何时候点击Control- \输出堆转储,运行线程等。 。 。而不会弄糟你的应用程序代码。这有些过时,Java 6随GUI jconsole一起提供,但我仍然发现HPROF非常有用。
您也可以向JVM发送一个信号,通过向进程发送一个QUIT信号来在正在运行的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
注意Thread.dumpStack()实际上抛出一个异常:
new Exception("Stack trace").printStackTrace();
如果您需要捕捉输出
StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
的Java 9中引入了StackWalker
和支持类用于走栈。
这里是从的Javadoc的几个片段:
的
walk
方法打开的StackFrames
当前线程顺序数据流,然后应用给定函数走StackFrame
流。该流按照从表示生成堆栈的执行点的最顶部帧到最底部帧的顺序报告堆栈帧元素。当walk方法返回时,StackFrame
流将被关闭。如果尝试重新使用封闭流,则会抛出IllegalStateException
。...
为快照当前线程的顶部10的堆栈帧,
List<StackFrame> stack = StackWalker.getInstance().walk(s -> s.limit(10).collect(Collectors.toList()));
它可能最好使用现有的调试工具。他们中有很多人,你可以花时间在这个项目上工作,而不是重新发明一些东西。 除非你很乐意编写调试器,当然。 – 2009-06-03 19:52:26