6.8 Den Stack-Trace erfragen *
Bei jedem Methodenaufruf legt die JVM eine Kennung auf einen Aufrufstapel (eng. call stack). Um den Aufrufstapel zu einem bestimmten Zeitpunkt sichtbar zu machen, lässt sich ein Stack-Trace erfragen. Der Stack-Trace ist dabei allerdings nicht der Aufrufstapel selbst – Java setzt einige Abstraktionen über Maschinencode und gibt die internen Vorgänge nicht preis –, sondern eine Liste von StackTraceElement-Objekten. Jedes dieser Objekte bietet Zugriff auf den Namen der Datei, in der die Methode deklariert wurde, auf die Programmzeile, den Methodennamen und die Information darüber, ob die Methode nativ ist oder nicht.
Warum sind Stack-Traces nun nützlich? Einige Antworten:
- Strack-Traces sind unverzichtbare Aussagen im Fehlerfall und beim Debugging, denn Entwickler möchten gerne wissen, welchen Weg Aufrufe genommen haben.
- Sie helfen beim Erkennen von Rekursionen. Bei einer Rekursion ruft eine Methode direkt oder indirekt sich selbst auf. Das allein ist nicht problematisch, aber wenn eine Abbruchbedingung fehlt, so kommt es zu einer Endlosrekursion, was zum Platzen des Stack-Speichers führt und letztendlich zu einem StackOverflowError. Eine Untersuchung zur Laufzeit kann rekursive Aufrufe identifizieren und den Thread gleich abbrechen, anstatt dass der wild gewordene Thread etwa in jedem Methodenaufruf noch Speicher alloziert und es dann mit einem OutOfMemoryError noch schlimmer kommt.
- Methoden können durch Stack-Inspektionen Sicherheitsprüfungen durchführen, etwa nachschauen, ob ein Aufruf überhaupt autorisiert ist. Die Java Security basiert auf dieser Arbeitsweise, und ein Access Controller arbeitet genau für diesen Test den Stack ab.
6.8.1 StackTraceElement

Java bietet unterschiedliche Möglichkeiten, einen Stack-Trace zu erfragen und somit an eine Sammlung von StackTraceElement-Objekten zu kommen, die die Aufrufgeschichte zeigen:
- Bei einer ausgelösten Ausnahme verrät die Methode getStackTrace() vom Throwable-Objekt den aktuellen Stack-Trace.
- Ein Thread-Objekt gibt seine eigene Aufrufhierarchie mit getStackTrace() an. Jeder Thread hat einen eigenen Aufrufstapel.
- Die statische Methode Thread.getAllStackTraces() liefert für alle Threads die aktuellen Stack-Traces.
Die genannten Methoden liefern Sammlungen von StackTraceElement-Objekten mit folgenden Informationen:
final class java.lang.StackTraceElement |
- String getClassName()
- String getFileName()
- int getLineNumber()
- String getMethodName()
- boolean isNativeMethod()
Bedauerlicherweise fehlen wichtige Informationen, wie etwa Zeitpunkte.
6.8.2 printStackTrace()

Eine Methode, die in den Buchbeispielen schon oft zum Einsatz kam, war printStackTrace(): Sie gibt auf dem Bildschirm den Stack-Trace aus. Die Methode printStackTrace() stammt von Throwable und ist überladen; die Signaturen sind: printStackTrace(), printStackTrace(PrintStream) und printStackTrace(PrintWriter). Intern ruft printStackTrace() einfach printStackTrace(System.err) auf, sodass der Stack-Trace automatisch auf den Fehlerausgabekanal kommt.
class java.lang.Throwable |
- void printStackTrace()
Schreibt das Throwable und anschließend den Stack-Inhalt in den Standardausgabestrom. - void printStackTrace(PrintStream s)
Schreibt das Throwable und anschließend den Aufruf-Stack in den angegebenen PrintStream. - void printStackTrace(PrintWriter s)
Schreibt das Throwable und anschließend den Aufruf-Stack in den angegebenen PrintWriter.
6.8.3 StackTraceElement vom Thread erfragen
Sehen wir uns ein Beispielprogramm an, das mehrere Methoden aufruft und dann den Stack-Trace ausgibt:
Listing 6.29: GetStackTrace.java
public class GetStackTrace
{
public static void showTrace()
{
for ( StackTraceElement trace : Thread.currentThread().getStackTrace() )
System.out.println( trace );
}
public static void m( int n )
{
if ( n == 0 )
showTrace();
else
m( n – 1 );
}
public static void main( String[] args )
{
m( 2 );
}
}
Ein StackTraceElement deklariert eine toString()-Methode, und die Ausgabe sieht dann so aus:
java.lang.Thread.getStackTrace(Thread.java:1578)
GetStackTrace.showTrace(GetStackTrace.java:5)
GetStackTrace.m(GetStackTrace.java:12)
GetStackTrace.m(GetStackTrace.java:14)
GetStackTrace.m(GetStackTrace.java:14)
GetStackTrace.main(GetStackTrace.java:19)
class java.lang.Thread |
- static Map<Thread,StackTraceElement[]> getAllStackTraces()
Die statische Methode liefert von allen Threads in einem Assoziativspeicher ein Feld von StackTraceElement-Objekten. - StackTraceElement[] getStackTrace()
Liefert den Stack-Trace für den Thread.
Beispiel |
Finde heraus, in welcher Methode wir gerade stehen: StackTraceElement e = Thread.currentThread().getStackTrace()[2]; |
Realitätstest |
Der Stack-Trace, den Java bietet, ist relativ arm an Informationen, und die Standardausgabe über printStrackTrace() ist unübersichtlich. Zudem fehlen spannende Informationen wie Zeitpunkte, und ein getAllStackTraces() ist bei vielen Threads und tiefen Aufrufhierarchien sehr langsam. Summa summarum: Ein guter Debugger beziehungsweise ein Analysetool mit Zugriff auf die JVM-Eigenschaften ist für die ernsthafte Entwicklung unumgänglich. |
Ihr Kommentar
Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.