Чи є спосіб скинути слід стека, не кидаючи виняток у java?


159

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

Мені цікаво, чи можна отримати слід стека, як, Exception.printStackTrace()але насправді не кидати виняток?

Моя мета - у будь-якому даному методі скинути стек, щоб побачити, хто такий виклик методу.

Відповіді:


84

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


250

Так, просто використовуйте

Thread.dumpStack()

44
... але не кидає.
Роб

5
Це відповідь, яка насправді вирішує питання.
бруно

7
Дуже просто і елегантно. Це мала бути прийнятою відповіддю.
deLock

11
Fwiw, джерело цього методу: public static void dumpStack() { new Exception("Stack trace").printStackTrace(); }
JohnK

Це, безумовно, найкраща відповідь на питання, якщо ви задоволені результатами stderr, що, мабуть, є наслідком цього питання.
мійський гризун

46

Якщо ви хочете простежити лише поточний потік (а не всі потоки в системі, як це пропонує пропозиція Рама), зробіть:

Thread.currentThread (). getStackTrace ()

Щоб знайти абонента, виконайте:

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

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


2
Тому просто створіть новий Виняток самостійно та використовуйте [1] як індекс!
Даніель

3
У заголовку цього питання написано "не кидаючи винятку". Зрозуміло, ви пропонуєте створити виняток, але не кидати його, але я все одно думаю, що це не в дусі питання.
Том Андерсон

1
Звичайно, так і є. Створення винятку - це найнижчий спосіб отримати стек-трек. Навіть ваш Thread.currentThread (). GetStackTrace () робить це, але мій спосіб робить це швидше :).
Даніель

@Daniel Є ще одне враження: з багатьма тестовими рамками, наприклад, Споком, для створення рамки буде достатньо лише створення винятку (не кидаючи його): тест вважатиме, що виняток "стався", і тест буде кінець, з провалом.
мійський гризун

@mikerodent: Ви впевнені? Споку доведеться використовувати агенти для цього. Але все одно, тому що мені просто потрібно було викликати клас, я використовував Reflection.getCallerClass (2) у функції утиліти. Ви не отримаєте функцію та номер рядка таким чином, подумав.
Даніель

37

Ви можете отримати такий слід стека:

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

Якщо ви хочете отримати доступ до кадру, ви можете використовувати t.getStackTrace (), щоб отримати масив фреймів стеків.

Майте на увазі, що в цьому стек-трасі (як і в будь-якому іншому) можуть бути відсутні кадри, якщо компілятор точки доступу зайнятий оптимізацією речей.


Мені подобається ця відповідь, оскільки вона пропонує мені можливість направляти результати. Я можу замінити t.printStackTraceна t.printStackTrace(System.out).

4
В одному рядку:new Throwable().printStackTrace(System.out);

1
Це має бути прийнятою відповіддю. Це просто і прямо вперед! Дякуємо за обмін
Сем

2
і його легко надіслати на java.util.Loggerlog.log(Level.SEVERE, "Failed to do something", new Throwable());
MitchBroadhead

13

Зауважте, що Thread.dumpStack () насправді викидає виняток:

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

12
Це створює виняток, але не кидає його.
MatrixFrog

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


6

Якщо вам потрібен вихід для захоплення

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

6

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

HPROF Java Profiler

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


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.