2009-06-03 9 views
118

Je pense à créer un outil de débogage pour mon application Java.Existe-t-il un moyen de vider une trace de pile sans lancer une exception dans Java?

Je me demande s'il est possible d'obtenir une trace de pile, tout comme Exception.printStackTrace() mais sans réellement lever une exception?

Mon but est, dans une méthode donnée, de vider une pile pour voir qui est l'appelant de la méthode.

+2

Il est probablement préférable d'utiliser un outil de débogage existant. Il y en a beaucoup, et vous pouvez passer ce temps à travailler sur le projet au lieu de réinventer quelque chose. Sauf si vous vous amusez à écrire un débogueur, bien sûr. –

Répondre

69

Vous pouvez également essayer Thread.getAllStackTraces() d'obtenir une carte de traces de pile pour tous les fils qui sont vivants.

+4

+1, certainement utile s'il veut analyser la trace de la pile! –

174

Oui, il suffit d'utiliser

Thread.dumpStack() 
+18

... qui crée une nouvelle exception, et appelle 'printStackTrace()' dessus. – erickson

+38

... mais ne le lance pas. – Rob

+0

C'est la réponse qui répond réellement à la question. – bruno

23

Vous pouvez obtenir une trace de pile comme ceci:

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

Si vous souhaitez accéder au cadre, vous pouvez utiliser t.getStackTrace() pour obtenir un tableau d'images de pile. Sachez que cette pile (comme n'importe quelle autre) peut manquer certaines images si le compilateur de hotspot a été occupé à optimiser les choses.

+0

J'aime cette réponse parce qu'elle me donne l'opportunité de diriger la sortie. Je peux remplacer 't.printStackTrace' par' t.printStackTrace (System.out) '. –

+2

Dans une ligne: 'new Throwable(). PrintStackTrace (System.out);' –

+0

Ceci devrait être la réponse acceptée. C'est simple et direct! Merci de partager – Sam

31

Si vous voulez la trace juste le thread courant (plutôt que tous les fils dans le système, comme le fait la suggestion de Ram), faites:

Thread.currentThread(). getStackTrace()

Pour l'appelant, faire:

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

Et appeler cette méthode à partir de la méthode qui a besoin de savoir qui est son interlocuteur. Cependant, un mot d'avertissement: l'index du cadre appelant dans la liste pourrait varier en fonction de la JVM! Tout dépend du nombre de couches d'appels dans getStackTrace avant que vous n'atteigniez le point où la trace est générée. Une solution plus robuste consisterait à obtenir la trace et à la parcourir en cherchant le cadre de getCallingMethodName, puis à remonter de deux pas pour trouver le véritable appelant.

+1

Il suffit donc de créer une nouvelle exception et d'utiliser [1] comme index! – Daniel

+2

Le titre de cette question dit "sans lancer d'exception". Certes, vous suggérez de créer l'exception sans la lancer, mais je pense toujours que ce n'est pas dans l'esprit de la question. –

+0

Bien sûr que oui. Créer une exception est le moyen le plus bas pour obtenir une pile de pile. Même votre Thread.currentThread(). GetStackTrace() le fait, mais mon chemin le fait plus vite :). – Daniel

0

HPROF Java Profiler

Vous n'avez même pas le faire dans le code. Vous pouvez attacher le Java HPROF à votre processus et, à tout moment, appuyer sur Control- \ pour afficher le tas de mémoire, exécuter des threads, etc. . . sans déblayer votre code d'application. C'est un peu dépassé, Java 6 est livré avec la jconsole GUI, mais je trouve toujours HPROF très utile.

5

Vous pouvez également envoyer un signal à la machine virtuelle Java pour exécuter Thread.getAllStackTraces() sur un processus Java en cours d'exécution en envoyant un signal QUIT au processus.

Sur Unix/Linux utilisent:

kill -QUIT process_id, où id_processus est le numéro de processus de votre programme Java.

Sous Windows, vous pouvez appuyer sur Ctrl-Pause dans l'application, bien que vous ne voyiez généralement rien à moins que vous n'effectuiez un processus de console.

JDK6 introduit une autre option, la commande jstack, qui affiche la pile de tout processus JDK6 en cours d'exécution sur votre ordinateur:

jstack [-l] <pid>

Ces options sont très utiles pour les applications qui sont en cours d'exécution dans un environnement de production et ne peut pas être modifié facilement. Ils sont particulièrement utiles pour diagnostiquer les blocages d'exécution ou les problèmes de performance.

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

11

Notez que Thread.dumpStack() renvoie en fait une exception:

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

Il crée une exception, mais ne la lance pas. – MatrixFrog

3

Si vous avez besoin capturer la sortie

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

Java 9 introduit les classes StackWalker et de soutien pour marcher la pile.

Voici quelques extraits de la Javadoc:

La méthode walk ouvre un flux séquentiel de StackFrames pour le thread courant et applique la fonction donnée à marcher le flux StackFrame. Le flux rapporte les éléments du cadre de pile dans l'ordre, à partir de la partie la plus haute du cadre qui représente le point d'exécution auquel la pile a été générée jusqu'à la partie inférieure de la trame. Le flux StackFrame est fermé lorsque la méthode de retour est rétablie. Si une tentative est faite pour réutiliser le flux fermé, IllegalStateException sera lancé.

...

  1. Snapshot les 10 cadres de pile du thread courant,

    List<StackFrame> stack = StackWalker.getInstance().walk(s -> 
    s.limit(10).collect(Collectors.toList())); 
    
Questions connexes