Есть ли способ сбросить трассировку стека, не выбрасывая исключение в java?

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

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

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

Ответ 1

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

Ответ 2

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

Thread.dumpStack()

Ответ 3

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

Thread.currentThread(). getStackTrace()

Чтобы найти вызывающего абонента, выполните:

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

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

Ответ 4

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

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

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

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

Ответ 5

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

new Exception("Stack trace").printStackTrace();

Ответ 6

Вы также можете отправить сигнал 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

Ответ 7

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

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

Ответ 8

HPROF Java Profiler

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

Ответ 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()));