2010-01-13 12 views

Respuesta

20

Así que en realidad solo tuve que descubrir cómo hacer esto: todavía no he usado esta solución de forma exhaustiva en la producción, pero hay una biblioteca relativamente nueva llamada ClrMd.

http://blogs.msdn.com/b/dougste/archive/2013/05/04/clrmd-net-crash-dump-and-live-process-inspection.aspx

Con ella, yo soy capaz de conectar a mi propio proceso y obtener un seguimiento de pila para todos los hilos en vivo.El uso de este cuando se detecta un punto muerto antes de reiniciar nuestra aplicación de este modo:

var result = new Dictionary<int, string[]>(); 

var pid = Process.GetCurrentProcess().Id; 

using (var dataTarget = DataTarget.AttachToProcess(pid, 5000, AttachFlag.Passive)) 
{ 
    string dacLocation = dataTarget.ClrVersions[0].TryGetDacLocation(); 
    var runtime = dataTarget.CreateRuntime(dacLocation); 

    foreach (var t in runtime.Threads) 
    { 
     result.Add(
      t.ManagedThreadId, 
      t.StackTrace.Select(f => 
      { 
       if (f.Method != null) 
       { 
        return f.Method.Type.Name + "." + f.Method.Name; 
       } 

       return null; 
      }).ToArray() 
     ); 
    } 
} 

var json = JsonConvert.SerializeObject(result); 

zip.AddEntry("_threads.json", json); 

Lo realmente importante para conseguir que para trabajar desde el mismo proceso es AttachFlag.Passive

Si usted acaba de hacer DataTarget.AttachToProcess(pid, 5000), que va a hacer una conexión "invasiva" que intenta detener el proceso. Esto arroja una excepción cuando intenta adjuntar a su propio proceso, lo asumo porque no puede pausar su aplicación mientras intenta adjuntar desde su aplicación o algo así.

De todos modos, sí, cosas muy interesantes.

Si alguien tiene alguna razón por la cual esto es súper ingenuo o algo así, por favor, señálelos. Todavía no lo he usado en producción (solo apagué la primera instancia), así que espero que funcione.

+0

Acabo de recuperar algunos volcados de depuración desde una ubicación de cliente y esto funcionó para nosotros. muy genial. –

+0

¡Gran código, gracias! Podría sugerir agregar la firma del método como con f.Method.GetFullSignature(). Puede ser útil en caso de invalidaciones – Andrey

+0

Solo una actualización: he obtenido resultados de esto de una gran cantidad de instalaciones de clientes y siempre ha funcionado y ha sido útil. –

-5

Puede recorrer en System.Diagnostics.Process.GetCurrentProcess(). Hilos y para cada hilo crear un objeto StackTrace con la que se lleva a .ctor un hilo como su param.

+4

Al igual que con la respuesta de @ MarcosMeli, esto es incorrecto. Como dice @Hans Loken, el método GetCurrentProcess() devuelve un ProcessThreadCollection que contiene objetos ProcessThread, no objetos Thread. Por lo que puedo decir, no se puede obtener un seguimiento de la pila de un ProcessThread, ya que representa el hilo nativo de Windows. –

-4

Prueba este

var proc = System.Diagnostics.Process.GetCurrentProcess(); 
var threads = proc.Threads; 

var res = new Dictionary<Thread, StackTrace>(); 
foreach (Thread thread in threads) 
{ 
    var stackTrace = new StackTrace(thread, true); 
    res.Add(thread, stackTrace); 
} 

En res u obtener el diccionario con el mapeo u desea :)

+11

Ejecutar ese código arroja una InvalidCastException para mí. Process.Threads devuelve un ProcessThreadCollection que contiene los objetos ProcessThread y no los objetos Thread. Además, no hay forma de convertir de un ProcessThread a un Thread, ya que ProcessThread representa los hilos del sistema operativo mientras que el hilo es de hilos .net. –

4

Si desea que esta solo con fines de depuración, las extensiones de SOS a WinDBG le puede dar esta información .

El comando para ejecutar es "* ~ e! Clrstack".

Dentro de un programa C# en ejecución, no hay forma pública de enumerar subprocesos administrados o buscarlos por ID. Incluso si pudiera, obtener un seguimiento de pila en un subproceso diferente probablemente requeriría su suspensión, lo que tiene algunos riesgos de efectos secundarios (consulte por qué this is obsolete).

La otra alternativa es enlistar hilos como se les conoce y escanearlos cuando lo desee. Esto probablemente solo sea posible si está creando explícitamente objetos de subprocesos en lugar de usar el grupo de subprocesos.

Dicho esto, también es difícil para mí ver para qué sirve este enfoque. Si se trata de depurar, existen técnicas mucho más poderosas que se pueden hacer en memoria o en mini-volcados. Si es para el registro, entonces podría tener sentido que las llamadas de registro contribuyan con sus propias pilas.

-1

Como sugiere Mason of Words, esto no parece posible desde el propio código administrado. ¿Podría aclarar por qué necesita esto: podría haber una solución mejor?

Por ejemplo, si se conecta al proceso en Visual Studio y presiona "pause", la ventana "Threads" mostrará una lista de todos los subprocesos administrados, y la ventana "Stacktrace" puede mostrar la traza actual de pila para cada subproceso. ¿Eso sería suficiente?

Cuestiones relacionadas