2011-07-28 9 views
11

En los comentarios a un answer I wrote tuvimos una discusión sobre fugas de memoria y IDisposable donde no llegamos a ninguna conclusión real.¿Se ignorarán las fugas de memoria de causas descartables?

Una clase que maneja recursos no administrados probablemente implemente IDisposable. Si lo ignora y no llama al Dispose ni envuelve el objeto en un using, ¿dará lugar a que se filtre el recurso no administrado? ¿O se limpiará adecuadamente cuando el GC recolecte el objeto?

Podemos suponer que el manejo del recurso no administrado clase tiene una aplicación correcta de IDisposable, incluyendo finalizador etc.

+0

http://www.bluebytesoftware.com/blog/2005/04/08/DGUpdateDisposeFinalizationAndResourceManagement.aspx –

+1

Suponiendo que las cosas se hacen correctamente puede ser una cosa peligrosa. Pero aun así, esto está relacionado: http://stackoverflow.com/questions/6652044/c-language-garbage-collection-suppressfinalize/6652318#6652318 –

+3

Hay muchas situaciones en las que no se puede escribir un finalizador correcto porque Finalize es llamado en un hilo diferente de Dispose se invocará si se llama normalmente. –

Respuesta

14

No causará una pérdida de memoria . De hecho, Dispose no tiene absolutamente nada que ver con la gestión de la memoria.

Creará un recurso-escape. Y aunque el GC usualmente lo limpia, esto podría ser muy poco frecuente y demasiado tarde.

Omitir la eliminación (using) puede ralentizar o incluso bloquear su aplicación. En el caso de recursos de archivos o conexiones de Db, incluso puede causar problemas en otras aplicaciones.

+1

Ignorar IDisposable puede causar que un programa que se ejecute en una cantidad limitada de memoria (si IDisposable se usó correctamente) requiera una cantidad ilimitada de memoria. Si el crecimiento ilimitado e innecesario de los requisitos de memoria de un programa se considera una pérdida de memoria, ignorar IDisposable puede causar una pérdida de memoria. – supercat

+0

@Supercat: Total balderdash, por las razones indicadas anteriormente.Quizás quisiste decir "cantidad limitada de recursos", pero eso es solo repetir la respuesta. –

+0

Supongamos que un IEnumerator se suscribe a un INotifyCollectionChangedEvent para permitir la enumeración práctica de una colección cambiante (un paradigma útil, por cierto, y uno que es compatible con la clase VisualBasic.Collection). A menos que la colección y el enumerador incluyan alguna lógica complicada para asegurar la finalización (tal lógica no es fácil, y agrega una sobrecarga considerable) IEnumeradores que no están Dispuestos tendrán su vida extendida a la de la colección. Dado que no existe un límite en la cantidad de veces que se puede enumerar una colección ... – supercat

9

no haré lograron pérdidas de memoria. Es puede causar fugas en el código no administrado al que se hace referencia. Pero es peor que eso: la memoria en los sistemas modernos es lo suficientemente abundante como para que puedas salir adelante por un tiempo con una mala fuga. Testigo de Mozilla Firefox: solía (¿todavía?) Gotear como un colador, y millones estaban felices de usarlo.

El problema más grande es otros recursos que pueden no tener nada que ver con la memoria en absoluto. Los ejemplos incluyen conexiones de bases de datos, controladores de E/S del sistema, identificadores de socket, manejadores de archivos y similares. Todos estos son elementos donde puede crear fácilmente situaciones de denegación de servicio en su propio sistema si no tiene cuidado de usar IDisposable correctamente.

+0

Un programa que crea y abandona un número ilimitado de suscriptores de eventos para un objeto de larga duración requerirá una cantidad ilimitada de memoria para contener a esos suscriptores, incluso si el número de suscriptores no abandonados en un momento determinado nunca crece más allá de una constante (o, para el caso, uno). Tales suscripciones abandonadas ciertamente cumplirían mi definición de una pérdida de memoria (la cantidad de memoria requerida para que un programa maneje alguna secuencia de entrada no tiene límites con respecto a la cantidad de estado "útil" que contiene). – supercat

2

Si un objeto IDisposable tiene un finalizador que desasigna la memoria no administrada, la memoria estará libre cuando se llame al finalizador (una vez marcado para su recolección por el GC y colocado en la cola del finalizador), pero si no existe No se llama nunca a ningún finalizador ni a Dispose(), luego se puede filtrar la memoria y solo volver a reclamarse cuando finaliza el proceso.

0

Que yo sepa el GC no llamará a Dispose. Tienes que llamarlo tú mismo explícitamente o usar usar. Entonces la respuesta es: Sí, si la clase maneja recursos no administrados, que se liberan en Dispose, su clase tendrá fugas, si no llama a Dispose.

+3

Esto no es estrictamente cierto, ya que solo se "filtrará" hasta que se ejecute el finalizador. Esto se basa en la gran suposición de que han implementado correctamente 'IDisposable'. – user7116

+2

Pero cualquier clase IDisposable adecuada también liberará los recursos en el destructor (GC). –

+1

@Henk Holterman: Las clases identificables que pueden, prácticamente, recuperarse del abandono inapropiado utilizando Finalize deberían hacerlo. Tal recuperación no siempre es práctica, sin embargo. El código que abandona objetos identificables sin saber que * esos objetos particulares * pueden abandonarse de forma segura está mucho más roto que los objetos identificables que dejan las cosas en mal estado cuando se abandonan. – supercat

4

sólo para añadir un poco de Henk y respuestas de Joel

Lo que usted ha descrito sucede muy a menudo en el DB conexiones específicamente. Basta con que se haya agregado ADO.NET Performance counterNumberOfReclaimedConnections. Este contador rastrea ...

El número de conexiones que han sido recuperados en la basura colección donde Cerrar o disponer no fue llamado por la aplicación. No cerrar o eliminar conexiones explícitamente perjudica el rendimiento.

El golpe de rendimiento suele ser más largo que el necesario, espere a que se libere la conexión. Esto también puede provocar tiempos de espera en la conexión, no un problema de memoria.

1

No poder llamar IDisposable en objetos que se suscriban a eventos de objetos de vida más larga extenderá la duración de la asignación de memoria del suscriptor para que se extienda a la del editor. Si no hay un límite superior para la cantidad de suscriptores que pueden adjuntarse y abandonarse durante la vida útil de un editor, esto constituirá una pérdida de memoria ilimitada.

1

El gran problema es cuando se ejecuta GC.

tomar las siguientes clases

class GcTest 
{ 
    private Stopwatch sw = new Stopwatch(); 
    public GcTest() 
    { 
     sw.Start(); 
    } 

    ~GcTest() 
    { 
     sw.Stop(); 
     Console.WriteLine("GcTest finalized in " + sw.ElapsedMilliseconds + " ms"); 
    } 
} 

Ponga un punto de interrupción en el Console.WriteLine si lo desea.

Crear una aplicación ventanas vacías forma, y ​​en el caso de carga del formulario simplemente una instancia de un nuevo GcTest

private void Form1_Load(object sender, EventArgs e) 
{ 
    var gcTest = new GcTest(); 
} 

ejecutar la aplicación y esperar a que el finalizador para funcionar.
Lo más probable es que no se ejecute hasta que cierre su aplicación.