Есть ли способ вывести трассировку стека без выдачи исключения в Java? - PullRequest
139 голосов
/ 03 июня 2009

Я думаю о создании инструмента отладки для моего Java-приложения.

Мне интересно, возможно ли получить трассировку стека, точно так же как Exception.printStackTrace(), но на самом деле не выбрасывать исключение?

Моя цель состоит в том, чтобы в любом данном методе сбросить стек, чтобы увидеть, кто является вызывающим методом.

Ответы [ 9 ]

214 голосов
/ 03 июня 2009

Да, просто используйте

Thread.dumpStack()
77 голосов
/ 03 июня 2009

Вы также можете попробовать Thread.getAllStackTraces(), чтобы получить карту трассировки стека для всех потоков, которые живы.

38 голосов
/ 03 июня 2009

Если вам нужна трассировка только для текущего потока (а не для всех потоков в системе, как советует Рам), выполните:

Thread.currentThread (). getStackTrace ()

Чтобы найти абонента, выполните:

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

И вызовите этот метод из метода, который должен знать, кто его вызывает. Однако, предупреждающее слово: индекс вызывающего кадра в списке может варьироваться в зависимости от JVM! Все зависит от того, сколько слоев вызовов есть в getStackTrace, прежде чем вы достигнете точки, где генерируется трассировка. Более надежным решением было бы получить трассировку и выполнить итерацию по ней, ища фрейм для getCallingMethodName, а затем сделать еще два шага вверх, чтобы найти истинного абонента.

32 голосов
/ 03 июня 2009

Вы можете получить трассировку стека следующим образом:

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

Если вы хотите получить доступ к фрейму, вы можете использовать t.getStackTrace (), чтобы получить массив фреймов стека.

Имейте в виду, что в этой трассировке стека (как и в любом другом) могут отсутствовать некоторые кадры, если компилятор горячей точки был занят оптимизацией.

13 голосов
/ 31 января 2013

Обратите внимание, что Thread.dumpStack () фактически выдает исключение:

new Exception("Stack trace").printStackTrace();
6 голосов
/ 03 июня 2009

Вы также можете отправить сигнал в JVM для выполнения Thread.getAllStackTraces () в работающем процессе Java, отправив сигнал QUIT процессу.

В 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

4 голосов
/ 04 апреля 2017

Если вам нужен вывод захвата

StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
3 голосов
/ 07 декабря 2017

Java 9 представила StackWalker и поддерживающие классы для обхода стека.

Вот несколько фрагментов из Javadoc:

Метод walk открывает последовательный поток StackFrames для текущего потока и затем применяет данную функцию для обхода потока StackFrame. Поток сообщает элементы фрейма стека по порядку, от самого верхнего фрейма, который представляет точку выполнения, в которой был сгенерирован стек, до самого нижнего фрейма. Поток StackFrame закрывается, когда возвращается метод ходьбы. Если предпринята попытка повторно использовать закрытый поток, будет выброшено IllegalStateException.

...

  1. Чтобы сделать снимок 10 лучших кадров стека текущего потока,

    List<StackFrame> stack = StackWalker.getInstance().walk(s ->
     s.limit(10).collect(Collectors.toList()));
    
0 голосов
/ 03 июня 2009

HPROF Java Profiler

Вам даже не нужно делать это в коде. Вы можете присоединить Java HPROF к вашему процессу и в любой момент нажать Control- \ для вывода дампа кучи, запуска потоков и т. , , не портя код вашего приложения. Это немного устарело, Java 6 поставляется с графическим интерфейсом jconsole, но я все еще считаю HPROF очень полезным.

...