2009-10-08 17 views
7

¿No es posible obtener un evento cuando comienza el GC? Quiero cronometrar cada GC individual para poder ver si las pausas en mi servidor se deben a GC u otra cosa.Eventos de inicio y parada del GC

El GC pausa todos los hilos .NET mientras se ejecuta, ¿verdad? (Excepto el hilo en el que se ejecuta, por supuesto). ¿Qué hay de los hilos no gestionados?

Gracias!

+0

Gracias por sus comentarios, eso fue rápido :-) Ya he estado buscando la respuesta por un tiempo, por lo que ya sé sobre estas sugerencias (primeros 3 comentarios). Quiero mostrar en una línea de tiempo cuando el GC está funcionando y cuando no lo está. Entonces, saber cuándo se hace, o cuánto tiempo ha estado usando desde la última colección, no servirá. Estoy bastante sorprendido de que aún no haya podido encontrar la solución, pero si no existe nada, intentaré escribir mi propia herramienta hax0r para hacerlo. gracias de nuevo! – Rabbit

Respuesta

3

Esto es para lo que sirve la API de generación de perfiles. Ver ICorProfilerCallback2::GarbageCollectionStarted y GarbageCollectionFinished.

Como se trata de un generador de perfiles, obviamente no es adecuado para el uso de rutina en un sistema de producción. Pero de todos modos parece que estás interesado principalmente en esto para fines de diagnóstico. Por lo tanto, valdría la pena comprobar si uno de los perfiladores comerciales ya ofrece esta función, o si los contadores de perfmon serían suficientes; ¡escribir su propio generador de perfiles podría ser una solución muy pesada!

+0

¡Esto es lo que estaba buscando! Es sobre todo un proyecto de hobby, por lo que la solución "terriblemente pesada" suena bien (hasta que me aburro y encuentro un nuevo proyecto de mascota :) ¡Gracias! – Rabbit

0

hilos no administrados no se ven afectados por el GC.

Puede ver el rendimiento del GC en el monitor de rendimiento, aquí hay un artículo sobre cómo crear un monitor de sistema. Creo que puedes obtener un contador para el GC de alguna manera.

Codeproject

Aquí es una descripción de los contadores de Potencia utilizada por el GC

GC counters

1

La GC no emite ningún evento, pero se puede utilizar un temporizador y llamar para ver GC.CollectionCount() cuando se ha producido una colección.

0

El contador de rendimiento % Time in GC debe proporcionarle los datos que desea.

5

Hay una manera mucho más fácil si todo lo que quiere hacer es descubrir cuándo se está ejecutando GC, no le dirá exactamente cuándo comienza, ni cuándo terminará, pero si puede ver el resultado de esto método que describiré aquí cuando notes las pausas en tus servidores, deberías ser capaz de averiguar si GC es tu problema.

Básicamente, lo que debes hacer es crear una clase con un finalizador, construir un objeto de esa clase y simplemente soltar la referencia (es decir, no almacenarla). El objeto se dejará hasta que GC lo golpee, donde se finalizará.

El truco ahora está en el finalizador que registra (de la manera que quiera usar) que el finalizador haya ejecutado, y a menos que el dominio de aplicación esté en proceso de cierre, simplemente construye un nuevo objeto que cae rápidamente la referencia a, listo para el próximo CG.

Esto funciona sorprendentemente bien y no necesita mucho trabajo de su parte.

Aquí está la clase que utilizo:

namespace PresentationMode 
{ 
    /// <summary> 
    /// This class is used to get a running log of the number of garbage collections that occur, 
    /// when running with logging. 
    /// </summary> 
    public sealed class GCLog 
    { 
     #region Construction & Destruction 

     /// <summary> 
     /// Releases unmanaged resources and performs other cleanup operations before the 
     /// <see cref="GCLog"/> is reclaimed by garbage collection. 
     /// </summary> 
     ~GCLog() 
     { 
      SiAuto.Main.LogMessage("GARBAGE COLLECTED"); 
      if (!AppDomain.CurrentDomain.IsFinalizingForUnload() && !Environment.HasShutdownStarted) 
       new GCLog(); 
     } 

     #endregion 

     #region Public Static Methods 

     /// <summary> 
     /// Registers this instance. 
     /// </summary> 
     public static void Register() 
     { 
#if DEBUG 
      if (SiAuto.Si.Enabled) 
       new GCLog(); 
#endif 
     } 

     #endregion 
    } 
} 

Todo lo que tiene que hacer es llamar al método .Register(). Tenga en cuenta que uso SmartInspect como herramienta de registro, por lo que desea reemplazar las llamadas relacionadas con SiAuto con otra cosa.

En otro proyecto, también usando SmartInspect, que tiene la noción de 'relojes', donde puede enviar valores numéricos y graficarlos en la herramienta de registro, envié los valores 0, 1 y luego 0 en rápida sucesión , ya que esto me daría un gráfico que se mantuvo en 0 en todo momento, pero produjo un pico agudo cada vez que había un GC funcionando. Unir esto con un hilo de fondo que monitorea el uso de la CPU y la memoria utilizada me dio datos muy buenos para trabajar.