2012-01-27 15 views
5

This artículo dice¿Por qué las clases con finalizadores necesitan más de un ciclo de recolección de basura?

Si un objeto tiene un finalizador, no se elimina inmediatamente cuando el recolector de basura decide que ya no es ‘en vivo’. En cambio, se convierte en un tipo especial de raíz hasta que .NET ha llamado al método del finalizador. Esto significa que estos objetos generalmente requieren más de una recolección de basura para ser eliminados de la memoria, ya que sobrevivirán al primer tiempo que no se usen.

Mi pregunta es por qué GC no llama al finalizador cuando descubre que el objeto ya no se puede referenciar y recoge el objeto de inmediato? ¿Por qué necesita más que en la recolección de basura?

Respuesta

6

dos puntos a considerar:

  • El finalizador puede tardar algún tiempo en completarse. Por ejemplo, puede terminar cerrando un recurso o algo similar. No querrá que sea parte del tiempo de recolección de basura, que puede estar bloqueando el trabajo de los subprocesos (cuando solo quieren obtener algo de memoria). Al ejecutar la finalización por separado, el GC puede completarse muy rápidamente, y el trabajo de finalización puede realizarse en paralelo con otro trabajo posterior.

  • El finalizador puede resucitar el objeto haciéndolo visible de nuevo, pero la detección de eso (sospecho) requiere otro barrido de memoria de todos modos ... así que ¿por qué no esperar hasta la próxima vez que vaya a suceder?

3

Porque (dependiendo del modo GC seleccionado) cuando se está realizando GC it has to pause key parts of the runtime. Por lo tanto, quiere que esto sea lo más rápido posible. Esto crea dos problemas:

  1. que no sabe cuánto tiempo el finalizador se llevará a funcionar (aunque tiene un límite duro), y no quiere retrasar la reanudación de la ejecución
  2. el tiempo de ejecución necesario estar en ejecución para el finalizador para funcionar de forma fiable (incluso si se utiliza un hilo de GC, el código que escriba concebible que se preocupan por otros hilos)

abordar ambas cuestiones, los que tienen finalizadores pendientes en cola, y luego ejecutados después de, el GC ha finalizado (cuando el tiempo de ejecución está funcionando).

Como nota al margen, es una buena práctica combinar los finalizadores con IDisposable y tener el Dispose() cancelar la finalización; de esa manera no necesita finalización posterior, y se limpia en un solo paso.

0

Cuando el .net recolector de basura se ejecuta, los objetos se dividen en tres categorías: los objetos que son accesibles desde una referencia "normal" arraigados, objetos que no son accesibles por cualquier referencia arraigada, y objetos que no son accesibles por ninguna referencia rooteada "normal", pero han solicitado recibir una notificación cuando se abandonan, o son accesibles desde otros objetos que lo han hecho. El recolector de basura hace una lista de objetos en esa tercera categoría; esa lista se almacena como una referencia rooteada, haciendo que todos los objetos en ella 'vivan'.El sistema revisa los elementos de esa lista, sin embargo, cancela sus solicitudes de 'notificación', ejecuta su método Finalize() y los elimina de la lista. Si no existe ninguna referencia al objeto en cualquier lugar una vez que todo está dicho y hecho, entonces el objeto será declarado "muerto" en el siguiente ciclo de GC.

Cuestiones relacionadas