2009-06-03 23 views
118

Estoy pensando en crear una herramienta de depuración para mi aplicación Java.¿Hay alguna manera de volcar un seguimiento de pila sin lanzar una excepción en java?

Me pregunto si es posible obtener un seguimiento de la pila, al igual que Exception.printStackTrace() pero sin realmente lanzar una excepción?

Mi objetivo es, en cualquier método dado, volcar una pila para ver quién es el método que llama.

+2

Es probablemente mejor usar una herramienta de depuración existente. Hay muchos de ellos por ahí, y puede pasar ese tiempo trabajando en el proyecto en lugar de reinventar algo. A menos que te estés divirtiendo escribiendo un depurador, por supuesto. –

Respuesta

69

También puede intentar Thread.getAllStackTraces() para obtener un mapa de seguimientos de pila para todos los hilos que están vivos.

+4

+1, ¡definitivamente útil si quiere analizar el seguimiento de la pila! –

174

Sí, basta con utilizar

Thread.dumpStack() 
+18

... que crea una nueva excepción y llama a 'printStackTrace()' en ella. – erickson

+38

... pero no lo arroja. – Rob

+0

Esa es la respuesta que realmente aborda la pregunta. – bruno

23

, usted puede obtener un seguimiento de pila de esta manera:

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

Si desea acceder a la estructura, se puede utilizar t.getStackTrace() para obtener una matriz de marcos de pila.

Tenga en cuenta que a esta stacktrace (como cualquier otra) le pueden faltar algunos marcos si el compilador del punto de acceso ha estado ocupado optimizando las cosas.

+0

Me gusta esta respuesta porque me ofrece la oportunidad de dirigir la salida. Puedo reemplazar 't.printStackTrace' con' t.printStackTrace (System.out) '. –

+2

En una línea: 'new Throwable(). PrintStackTrace (System.out);' –

+0

Esta debería ser la respuesta aceptada. ¡Es simple y directo! Gracias por compartir – Sam

31

Si desea que el rastreo de sólo el hilo actual (en lugar de todos los hilos en el sistema, como lo hace la sugerencia de Ram), hacer:

Thread.currentThread(). getStackTrace()

Para encontrar la persona que llama, hacer:

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

y llamar a ese método desde dentro del método que necesita saber quién es su interlocutor. Sin embargo, una palabra de advertencia: ¡el índice del marco de llamada dentro de la lista podría variar de acuerdo con la JVM! Todo depende de cuántas capas de llamadas hay dentro de getStackTrace antes de llegar al punto donde se genera la traza. Una solución más robusta sería obtener la traza e iterar sobre ella buscando el marco para getCallingMethodName, luego dar dos pasos más hacia arriba para encontrar la verdadera persona que llama.

+1

¡Solo crea una nueva excepción por tu cuenta y usa [1] como índice! – Daniel

+2

El título de esta pregunta dice "sin tirar una excepción". De acuerdo, sugieres crear la excepción pero no arrojarla, pero todavía creo que no está en el espíritu de la pregunta. –

+0

Por supuesto que sí. Crear una excepción es la forma más sencilla de obtener una stacktrace. Incluso su Thread.currentThread(). GetStackTrace() lo hace, pero a mi manera lo hace más rápido :). – Daniel

0

HPROF Java Profiler

Ni siquiera tiene que hacer esto en el código. Puede adjuntar el HPROF de Java a su proceso y en cualquier momento presionar Control- \ para generar el volcado del heap, ejecutar subprocesos, etc. . . sin ensuciar el código de tu aplicación. Esto está un poco desactualizado, Java 6 viene con la GUI jconsole, pero todavía encuentro que HPROF es muy útil.

5

También puede enviar una señal a la JVM para ejecutar Thread.getAllStackTraces() en un proceso en ejecución de Java enviando una señal QUIT al proceso.

En Unix/Linux usar:

kill -QUIT process_id, donde id_proceso es el número de proceso del programa Java.

En Windows, puede presionar Ctrl-Break en la aplicación, aunque generalmente no verá esto a menos que esté ejecutando un proceso de consola.

JDK6 introdujo otra opción, el comando jstack, que muestra la pila de cualquier proceso JDK6 ejecutando en el equipo:

jstack [-l] <pid>

Estas opciones son muy útiles para aplicaciones que se ejecutan en un entorno de producción y no puede ser modificado fácilmente Son especialmente útiles para diagnosticar interbloqueos en tiempo de ejecución o problemas de rendimiento.

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

11

en cuenta que Thread.dumpStack() en realidad se produce una excepción:

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

Crea una excepción, pero no la arroja. – MatrixFrog

3

Si necesita capturar la salida

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

Java 9 introdujo las clases de apoyo y StackWalker para caminar la pila.

Éstos son algunos fragmentos de la Javadoc:

El método walk abre un flujo secuencial de StackFrames para el subproceso actual y luego se aplica la función dada a caminar por la corriente StackFrame. La secuencia informa los elementos del marco de la pila en orden, desde el marco superior que representa el punto de ejecución en el que se generó la pila hasta el marco inferior. La secuencia StackFrame se cierra cuando vuelve el método de caminata. Si se intenta reutilizar la secuencia cerrada, se lanzará IllegalStateException.

...

  1. Para una captura de los 10 marcos de pila superiores del hilo actual,

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