Pregunta

  

El destructor solo debe liberar recursos no administrados a los que se aferra su objeto, y no debe hacer referencia a otros objetos. Si solo tiene referencias administradas, no necesita (y no debe) implementar un destructor. Desea esto solo para manejar recursos no administrados. Debido a que tener un destructor tiene algún costo , debe implementar esto solo en métodos que consuman recursos valiosos y no administrados.

     

- Las diez principales trampas en C # para C ++ Programadores

El artículo no profundiza en esto, pero ¿qué tipo de costos implica el uso de un destructor en C #?

Nota: sé sobre el GC y el hecho de que no se llama al destructor en momentos confiables, aparte de eso, ¿hay algo más?

¿Fue útil?

Solución

Cualquier objeto que tenga un finalizador (prefiero ese término sobre destructor, para enfatizar la diferencia con los destructores de C ++) se agrega a la cola del finalizador. Esta es una lista de referencias a objetos que tiene un finalizador que debe llamarse antes de que se eliminen.

Cuando el objeto está listo para la recolección de basura, el GC encontrará que está en la cola del finalizador y moverá la referencia a la cola freachable (f-alcanzable). Esta es la lista por la que pasa el subproceso de fondo del finalizador para llamar el método del finalizador de cada objeto por turno.

Una vez que se ha llamado al finalizador del objeto, el objeto ya no está en la cola del finalizador, por lo que es solo un objeto administrado regular que el GC puede eliminar.

Todo esto significa que si un objeto tiene un finalizador, sobrevivirá al menos una recolección de basura antes de que pueda eliminarse. Por lo general, esto significa que el objeto se moverá a la siguiente generación de almacenamiento dinámico, lo que implica realmente mover los datos de la memoria de un almacenamiento dinámico a otro.

Otros consejos

La discusión más extensa que he tenido visto cómo funciona todo esto fue hecho por Joe Duffy . Tiene más detalles de los que puedas imaginar.

Después de eso, armé un enfoque práctico para hacer esto día a día, menos sobre el costo pero más sobre la implementación.

Guffa y JaredPar cubren los detalles bastante bien, así que solo agregaré una nota un tanto esotérica sobre los finalizadores o destructores, ya que la especificación del lenguaje C # lamentablemente los llama.

Una cosa a tener en cuenta es que dado que el subproceso finalizador ejecuta todos los finalizadores en secuencia, un interbloqueo en un finalizador evitará que se ejecuten todos los finalizadores restantes (y futuros). Dado que estas instancias no se recopilan hasta que sus finalizadores completen un finalizador interbloqueado, también se producirá una pérdida de memoria.

Este artículo cubre el problema en detalle. Es muy difícil resumirlo en una simple publicación SO: http: // msdn. microsoft.com/en-us/magazine/bb985010.aspx

Guffa ha resumido los factores en el costo finalizador bastante bien. Hubo un artículo reciente sobre el costo de los finalizadores en Java, que también da una idea.

Se puede evitar una parte del costo en .net eliminando el objeto de la cola del finalizador con GC.SuppressFinalize. Realicé algunas pruebas rápidas en .net según el artículo y lo publiqué aquí (aunque el enfoque está mucho más en el lado de Java).


A continuación se muestra un gráfico de los resultados: realmente no tiene las mejores etiquetas ;-). " Depurar = verdadero / falso " se refiere al finalizador vacío vs simple:

~ConditionalFinalizer()  
{  
    if (DEBUG)  
    {  
        if (!resourceClosed)  
        {  
            Console.Error.WriteLine("Object not disposed");  
        }  
        resourceClosed = true;  
    }  
} 

" Suprimir = verdadero " se refiere a si se llamó a GC.SuppressFinalize en el método Dipose.

Resumen

Para .net, eliminar el objeto de la cola del finalizador llamando a GC.SuppressFinalize es la mitad del costo de dejar el objeto en la cola.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top