2009-06-03 12 views
118

Mam na myśli stworzenie narzędzia do debugowania dla mojej aplikacji Java.Czy istnieje sposób do zrzutu śledzenia stosu bez wyjątku w java?

Zastanawiam się, czy można uzyskać ślad stosu, tak jak Exception.printStackTrace(), ale bez rzucania wyjątku?

Moim celem jest, aby w dowolnej metodzie zrzucić stos, aby zobaczyć, kto jest wywoływaczem metody.

+2

To chyba lepiej użyć istniejące narzędzie do debugowania. Jest ich wielu i możesz poświęcić ten czas na pracę nad projektem zamiast na nowo wymyślać coś. Oczywiście, jeśli nie masz nic przeciwko pisaniu debuggera. –

Odpowiedz

69

Możesz także spróbować Thread.getAllStackTraces() dostać mapę ślady stosu dla wszystkich wątków, które są żywe.

+4

+1, zdecydowanie przydatny, jeśli chce przeanalizować ślad stosu! –

174

Tak, wystarczy użyć

Thread.dumpStack() 
+18

... który tworzy nowy wyjątek i wywołuje na nim 'printStackTrace()'. – erickson

+38

... ale go nie wyrzuca. – Rob

+0

To jest odpowiedź, która w rzeczywistości odnosi się do pytania. – bruno

23

Można uzyskać ślad stosu tak:

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

Jeśli chcesz uzyskać dostęp do ramy, można użyć t.getStackTrace(), aby uzyskać tablica ramek stosu.

Należy pamiętać, że ten ślad stosu (podobnie jak każdy inny) może nie zawierać niektórych klatek, jeśli kompilator hotspotu był zajęty optymalizacją rzeczy.

+0

Podoba mi się ta odpowiedź, ponieważ daje mi możliwość kierowania wynikami. Mogę zastąpić 't.printStackTrace' przez' t.printStackTrace (System.out) '. –

+2

W jednym wierszu: 'new Throwable(). PrintStackTrace (System.out);' –

+0

To powinna być zaakceptowana odpowiedź. To proste i proste! Dziękujemy za udostępnienie – Sam

31

Jeśli chcesz ślad za jedyne bieżącego wątku (zamiast wszystkich wątków w systemie, jak sugeruje Ram), wykonaj:

Thread.currentThread(). getStackTrace()

Aby znaleźć rozmówcę, zrobić:

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

I wywołanie tej metody od wewnątrz metody, która musi wiedzieć, kim jest jego rozmówca. Jednak słowo ostrzeżenia: indeks ramki wywoławczej na liście może się różnić w zależności od JVM! Wszystko zależy od tego, ile warstw wywołań znajduje się w getStackTrace, zanim osiągniesz punkt, w którym generowany jest ślad. Bardziej niezawodnym rozwiązaniem byłoby pobranie śladu i powtórzenie go, szukając ramki dla metody getCallingMethodName, a następnie wykonaj dwa kroki w górę, aby znaleźć prawdziwego dzwoniącego.

+1

Po prostu utwórz nowy wyjątek i użyj [1] jako indeksu! – Daniel

+2

Tytuł tego pytania mówi "bez wyrzucania wyjątku". To prawda, sugerujesz utworzenie wyjątku, ale nie chcesz go wyrzucać, ale nadal uważam, że nie jest to zgodne z duchem pytania. –

+0

Oczywiście, że tak. Tworzenie wyjątku jest najbardziej niskopoziomowym sposobem na pobranie stosu. Nawet twój Thread.currentThread(). GetStackTrace() robi to, ale mój sposób robi to szybciej :). – Daniel

0

HPROF Java Profiler

Ty nawet nie masz to zrobić w kodzie. Możesz dołączyć Java HPROF do swojego procesu iw dowolnym momencie uderz w Control- \, aby wydrukować zrzut sterty, uruchomione wątki itp. . . bez fałszowania kodu aplikacji. To jest trochę nieaktualne, Java 6 ma jconsole GUI, ale nadal uważam, że HPROF jest bardzo użyteczny.

5

Można również wysłać sygnał do maszyny JVM, aby wykonać Thread.getAllStackTraces() na działającym procesie Java, wysyłając sygnał QUIT do procesu.

Na Unix/Linux używać:

kill -QUIT process_id, gdzie PROCESS_ID jest numerem procesu programu Java.

W systemie Windows możesz nacisnąć Ctrl-Break w aplikacji, chociaż zazwyczaj nie zobaczysz tego, chyba że korzystasz z konsoli.

JDK6 wprowadzono inną opcję, polecenie jstack, co spowoduje wyświetlenie stos z dowolnym systemem procesu JDK6 na komputerze:

jstack [-l] <pid>

Te opcje są bardzo przydatne dla aplikacji, które są uruchomione w środowisku produkcyjnym i nie można go łatwo modyfikować. Są one szczególnie przydatne do diagnozowania zakleszczeń w czasie pracy lub problemów z wydajnością.

http://java.sun.com/developer/technicalArticles/Programming/Stacktrace/ http://java.sun.com/javase/6/docs/technotes/tools/share/jstack.html

11

Uwaga, Thread.dumpStack() faktycznie zgłasza wyjątek:

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

Tworzy wyjątek, ale go nie wyrzuca. – MatrixFrog

3

Jeśli trzeba przechwycić wyjście z

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

Java 9 wprowadził StackWalker i zajęcia wspierające za chodzenie po stosie.

Oto kilka fragmentów z Javadoc:

Sposób walk otwiera sekwencyjny strumień StackFrames dla bieżącego wątku, a następnie stosuje się daną funkcję chodzić strumień StackFrame. Strumień zgłasza elementy ramek w stosie w kolejności od najbardziej najwyższej ramki, która reprezentuje punkt wykonawczy, w którym stos został wygenerowany do najbardziej dolnej ramki. Strumień StackFrame jest zamykany po powrocie metody walk. Jeśli nastąpi próba ponownego użycia zamkniętego strumienia, zostanie wygenerowany IllegalStateException.

...

  1. Aby migawkę top 10 klatek stos bieżącego wątku,

    List<StackFrame> stack = StackWalker.getInstance().walk(s -> 
    s.limit(10).collect(Collectors.toList())); 
    
Powiązane problemy