如何获得Java中的当前堆栈跟踪?


1001

我如何在Java中获取当前的堆栈跟踪,就像在.NET中可以做Environment.StackTrace什么一样?

我找到了,Thread.dumpStack()但这不是我想要的-我想找回堆栈跟踪信息,而不是打印出来。


73
当我在Eclipse中进行调试时,我总是使用“ new Exception()。printStackTrace()”作为监视表达式。当您在断点处暂停并想知道您来自哪里时,这很方便。
TimBüthe'09年

22
@TimBüthe:在调试模式下,Eclipse是否已不告诉您堆栈跟踪信息?我认同。
路易吉·马萨·加勒拉诺

41
Arrays.toString(Thread.currentThread()。getStackTrace()); 很简单。
2013年

2
@Arkanon它指的是Java,并显示了他们如何在.net中做到这一点以及Java中的等效功能。
Pokechu22

9
要很好地打印它,可以使用Apache StringUtils:StringUtils.join(currentThread()。getStackTrace(),“ \ n”);
艺术

Answers:


1158

您可以使用Thread.currentThread().getStackTrace()

这将返回一个StackTraceElements 数组,该数组代表程序的当前堆栈跟踪。


48
如果您已经在使用Apache Commons来获取字符串,那么这是一个很棒的工具:String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e); stackoverflow.com/a/10620951/11236
ripper234 2013年

5
数组中的第一个元素(索引0)是java.lang.Thread.getStackTrace方法,第二个元素(索引1)通常是第一个感兴趣的元素。
lilalinux 2014年

175
一个衬套将堆栈跟踪转换为在没有异常且未使用Apache Arrays.toString(Thread.currentThread()。getStackTrace())时有效的字符串
Tony

9
@Tony的解决方案是更好,因为它不需要抛出
MVD

3
正如下面许多答案所指出的那样- new Throwable().getStackTrace()速度更快,因为它不需要检查this != Thread.currentThread()并绕过通过子类(Exception extends Throwable)调用它的潜在JVM开销
Vlad 2015年

264
Thread.currentThread().getStackTrace();

如果您不在乎堆栈的第一个元素,那就很好了。

new Throwable().getStackTrace();

如果重要的话,将为您当前的方法定义位置。


35
(new Throwable()).getStackTrace()是更快的执行过(见bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302
MightyE

2
您能否更详细地说明Thread.currentThread()。getStackTrace()的结果与新的Throwable()。getStackTrace()有何不同?我同时尝试了两者,发现Thread.currentThread()。getStackTrace()返回索引为0的Thread.getStackTrace数组,并且调用方法位于索引1。新的Throwable()。getStackTrace()方法返回了带有调用的数组方法的索引为0。这两个方法似乎都为当前方法定义了位置,但是位置不同。您指出的另一个区别是吗?
瑞安(Ryan)

9
@Ryan,不能保证Thread.currentThread()。getStackTrace()不会保证在方法的不同版本上保持该位置。因此,当您恰巧检查它在索引1上时。在Sun的某个版本的JVM(1.5或1.6,不记得了)上,它是索引2。这就是我所定义的位置-规范要求它在那里,并在未来留在那里。
Yishai 2013年

5
@MightyE为已关闭的错误,现在报告为固定的Java 6纵观内部,它看起来像现在这样(new Exception()).getStackTrace()当请求的堆栈跟踪是当前线程(这将永远是对的情况下Thread.currentThread().getStackTrace();
M.贾斯汀

3
@MJustin:该错误尚未“立即”报告为已修复,甚至在MightyE撰写评论之前六年都已修复。实际上,它甚至在Stackoverflow建立之前就已得到修复……
Holger

181
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
    System.out.println(ste);
}

20
Java在Throwable上定义了一个printStackTrace方法,您可以这样做:new Exception().printStackTrace(System.out)我记得,for循环的开销可能较小,但是无论如何您都应该将此作为调试工作……
Jaap 2013年

2
我最喜欢这一点,因为您可以通过包装println语句来消除噪音,例如for (StackTraceElement ste : Thread.currentThread().getStackTrace()) { if(ste.toString().contains("mypackages")){ System.out.println(ste); } }
nby

61
Thread.currentThread().getStackTrace();

从JDK1.5开始可用。

对于较旧的版本,您可以重定向exception.printStackTrace()StringWriter()

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

3
new Throwable().getStackTrace()自JDK1.4起就可以使用…
Holger

40

您可以为此使用Apache的共同点:

String fullStackTrace = org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);

13
这是一个不错的单行解决方案。仅供参考,对于使用的任何人org.apache.commons.lang3,完整的行是:org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
fileoffset 2012年

2
只是为了重申fileoffset在移至时的注释org.apache.commons.lang3,我最初忽略了它-导入使用lang3代替lang,并替换getFullStackTracegetStackTrace
ggkmath13 2013年

那很有用!使用IDE(例如IntelliJ IDEA)进行调试时,最好使用ExceptionUtils.getStackTrace(new Throwable())表达式来获取堆栈跟踪。
谢尔盖·布鲁诺夫,


22

要获取所有线程的堆栈跟踪,可以使用jstack实用工具JConsole或发送kill -quit信号(在Posix操作系统上)。

但是,如果要以编程方式执行此操作,则可以尝试使用ThreadMXBean:

ThreadMXBean bean = ManagementFactory.getThreadMXBean();
ThreadInfo[] infos = bean.dumpAllThreads(true, true);

for (ThreadInfo info : infos) {
  StackTraceElement[] elems = info.getStackTrace();
  // Print out elements, etc.
}

如前所述,如果只需要当前线程的堆栈跟踪,则容易得多-只需使用Thread.currentThread().getStackTrace();


2
此答案中的代码段最接近以编程方式生成您在向JVM发送QUIT信号(在Unix之类的系统上)或Windows上的<ctrl> <break>时看到的转储。与其他答案不同,您可以看到监视器和同步器以及堆栈跟踪(例如,如果您遍历StackTraceElement数组并System.err.println(elems[i])在每个数组上执行)。摘要中的第二行bean.之前没有,dumpAllThreads但是我想大多数人都可以解决。
乔治·霍金斯

22

另一个解决方案(仅35个 31个字符):

new Exception().printStackTrace();   
new Error().printStackTrace();

1
很棒的解决方案。现在,我不必遍历所有堆栈帧
Vineel Kovvuri 2015年


17

作为对已接受答案的评论,Tony给出了实际上是回答OP问题的最佳答案:

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

...的OP也不要问如何获得String从一个堆栈跟踪Exception。而且,尽管我是Apache Commons的忠实拥护者,但是当事情像上面那样简单时,没有逻辑上的理由使用外部库。


我有一个线程列表,我需要打印它们的堆栈跟踪。
Daneel S. Yaitskov '17

在这种情况下,请确保使用Thread.getAllStackTraces(),它会给您一个Map<Thread, StackTraceElement[]>。热点将在需要安全指向一个线程时对所有线程进行安全指向。Zing可以将各个线程带到一个安全点,而不会干扰其他线程。获取stacktrace需要一个安全点。Thread.getAllStackTraces()获取所有堆栈跟踪并仅停止所有线程一次。当然,你必须找出哪些映射你真正感兴趣的。
拉尔夫^ h

14

我建议

  Thread.dumpStack()

这是一种更简单的方法,并且具有以下优点:在根本没有问题的情况下,实际上不构造异常或抛出异常,并且要点要多得多。


1
好的,实际上,dumpStack()是一个静态方法,应该以静态方式进行访问。谢谢,日食!
托马斯·阿德金斯

1
我喜欢该快捷方式,但是此方法的源代码是:new Exception("Stack trace").printStackTrace();因此,它实际上是在构建Throwable
Florent,

13

获取堆栈跟踪:

StackTraceElement[] ste = Thread.currentThread().getStackTrace();

打印堆栈跟踪(JAVA 8+):

Arrays.asList(ste).forEach(System.out::println);

打印堆叠(JAVA 7):

StringBuilder sb = new StringBuilder();

for (StackTraceElement st : ste) {
    sb.append(st.toString() + System.lineSeparator());
}
System.out.println(sb);

12

在Java 9中,有一种新方法:

public static void showTrace() {

  List<StackFrame> frames =
    StackWalker.getInstance( Option.RETAIN_CLASS_REFERENCE )
               .walk( stream  -> stream.collect( Collectors.toList() ) );

  for ( StackFrame stackFrame : frames )
    System.out.println( stackFrame );
}

有趣。:-)
djangofan

10

我有一个实用程序方法,该方法返回带有堆栈跟踪的字符串:

static String getStackTrace(Throwable t) {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw, true);
    t.printStackTrace(pw);
    pw.flush();
    sw.flush();
    return sw.toString();
}

就像...登录

... 
catch (FileNotFoundException e) {
    logger.config(getStackTrace(e));
}

这看起来像是由Netbeans自动生成的。
Leif Gruenwoldt 2012年

是记录器的内置记录器,还是您创建并写入文件的记录器。
Doug Hauf 2014年

@Doug Hauf,记录器是对内置Java Logger的引用。确保配置logging.properties文件。像这样在类的开头添加它:private static final Logger logger = Logger.getLogger(Your_Class_Name.class.getName());
萨尔瓦多·瓦伦西亚

1
java.util.logging.Logger#log(Level, String, Throwable)已经做到了。这是在不必要的情况下重写Java标准库中已经存在的内容,并为新开发人员指明了错误的方向,而该方向偏离了文档。现在,通过执行此操作,您已强制将Stacktrace格式化为某种格式,其中loggingAPI使您可以在指定时动态更改log语句的格式。据我所知,log4j也有类似的行为。不要重新发明轮子,因为您最终会失去我所解释的东西。
searchengine27年

1
它也存在于2012年。不幸的是,日期对您的情况没有影响。参见[link](docs.oracle.com/javase/1.5.0/docs/api/java/util/logging/Logger.html#log(java.util.logging.Level,java.lang.String,java.lang .Throwable)),[link](docs.oracle.com/javase/1.5.0/docs/api/java/util/logging/Logger.html#log(java.util.logging.LogRecord))等(还有是通过几个功能Throwable关闭的Handler通过到S FormatterS IN 2012这是Java7,比我在这里列出这些功能可以追溯到远长于Java7已经出现;因此J2SE 5.0的javadoc)
searchengine27

10

串入番石榴:

Throwables.getStackTraceAsString(new Throwable())

8
try {
}
catch(Exception e) {
    StackTraceElement[] traceElements = e.getStackTrace();
    //...
}

要么

Thread.currentThread().getStackTrace()

您的最佳示例不是仅给出相对于try / catch块的堆栈跟踪吗?
Dan Monego

1
两者之间有什么区别
twlkyao

5

也许您可以尝试以下方法:

catch(Exception e)
{
    StringWriter writer = new StringWriter();
    PrintWriter pw = new PrintWriter(writer);
    e.printStackTrace(pw);
    String errorDetail = writer.toString();
}

字符串“ errorDetail”包含堆栈跟踪。


5
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();

数组的最后一个元素表示堆栈的底部,这是序列中最近的方法调用。

A StackTraceElement has getClassName(), getFileName(), getLineNumber() and getMethodName().

遍历StackTraceElement并获得所需的结果。

for (StackTraceElement ste : stackTraceElements ) 
{
    //do your stuff here...
}

感谢您提到最后一个元素包含最新的元素。违反直觉,为我节省了一些时间。
clearlight

.toString()还将所有这些数据很好地输出到字符串中
Vlad 2015年

4

我从上面使用了答案并添加了格式

public final class DebugUtil {

    private static final String SEPARATOR = "\n";

    private DebugUtil() {
    }

    public static String formatStackTrace(StackTraceElement[] stackTrace) {
        StringBuilder buffer = new StringBuilder();
        for (StackTraceElement element : stackTrace) {
            buffer.append(element).append(SEPARATOR);
        }
        return buffer.toString();
    }

    public static String formatCurrentStacktrace() {
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        return formatStackTrace(stackTrace);
    }
}

2

如果要检查进程的当前调用堆栈,可以使用jstack实用程序。

Usage:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)

Options:
    -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
    -m  to print both java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message

1

这是旧帖子,但这是我的解决方案:

Thread.currentThread().dumpStack();

此处提供了更多信息和更多方法:http : //javarevisited.blogspot.fr/2013/04/how-to-get-current-stack-trace-in-java-thread.html


3
由于Thread.dumpStack()是静态的,因此您应该直接调用它。
David Avendasora

2
OP表示他们希望在代码中引用堆栈跟踪,而不是打印出来。
泰勒R

1
正如@DavidAvendasora提到的,您应该Thread.dumpStack()直接调用它,因为它是静态方法。
M-WaJeEh

是的,java.lang.Thread.dumpStack()适用于Java的11
公园JongBum

-3

System.out.println(Arrays.toString(Thread.currentThread().getStackTrace()));

这将帮助您打印没有循环的堆栈跟踪。


1
您的答案与3个月前发布的答案相同。
麦克啮齿动物
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.