2008-09-22 14 views
11

¿Qué recursos deben limpiarse manualmente en C# y cuáles son las consecuencias de no hacerlo?Recursos que deben limpiarse manualmente en C#?

Por ejemplo, decir que tengo el siguiente código:

myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black); 
// Use Brush 

Si no limpiar el cepillo utilizando el método dispose, estoy suponiendo que el recolector de basura libera la memoria utilizada al acabarse el programa? ¿Es esto correcto?

¿Qué otros recursos necesito para limpiar manualmente?

Respuesta

1

Técnicamente nada que herede de IDisposable debe desecharse de forma proactiva. Puede usar la declaración 'using' para facilitar las cosas.

http://msdn.microsoft.com/en-us/library/yh598w02.aspx

veces verá uso irregular de objetos IDisposable derivados en código de ejemplo documentación así como el código que se genera por las herramientas (es decir, el estudio visual).

Lo bueno de IDisposable es que le da la capacidad de de forma proactiva liberar el recurso subyacente no administrado. A veces realmente quieres hacer esto: piensa en las conexiones de red y los recursos de archivo, por ejemplo.

7
  • Maneja las estructuras de datos de las ventanas internas.
  • Conexiones de base de datos.
  • File handleles.
  • Conexiones de red.
  • Referencias COM/OLE.

La lista continúa.

Es importante llamar al Dispose o mejor aún, utilizar el patrón using.

using (SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black)) 
{ 
    // use myBrush 
} 

Si no desechar algo, que va a ser limpiado cuando los avisos recolector de basura que no hay más referencias a él, que pueden ser después de algún tiempo.

En el caso de System.Drawing.Brush, Windows mantendrá las estructuras internas de Windows para el pincel cargado en la memoria hasta que todos los programas liberen su asa.

2

En general, cualquier cosa que implemente IDisposable debería hacer que pause e investigue el recurso que está utilizando.

La GC solo ocurre cuando hay presión de memoria, por lo que no se puede predecir cuándo. Aunque una descarga del AppDomain ciertamente lo desencadenará.

-3

El recolector de basura se encargará de todos los recursos administrados. En su ejemplo, el cepillo se limpiará cuando el recolector de basura lo decida, lo que ocurrirá un tiempo después de que la última referencia al cepillo ya no sea válida.

Hay ciertas cosas que deben limpiarse manualmente, pero esos son punteros recuperados de fuentes no administradas, como llamadas a DLL, sin embargo, nada dentro de .NET Framework necesita este tratamiento.

+0

Esta respuesta tenía por objeto explicar cuándo _necesita_ limpiar sus recursos, no cuando debería, como lo hicieron otros. Por el tono de la pregunta original, supuse que esto era lo que se quería. – Guvante

0

Bueno, siempre que utilice la versión administrada de los recursos y no llame a las API de Windows por su cuenta, debería estar bien. Solo preocúpate por tener que eliminar/destruir un recurso cuando lo que obtienes es un IntPtr, ya que se conocen "manejadores de ventanas" (y muchas otras cosas) en .NET, y no un objeto.

Por cierto, el recurso (como cualquier otro objeto .NET) se marcará para la recopilación tan pronto como salga del contexto actual, por lo que si crea el pincel dentro de un método, se marcará cuando salga de él .

7

Si no dispone de algo, se limpiará cuando el recolector de basura advierta que no hay más referencias al mismo en su código, que puede ser después de un tiempo. Para algo así, en realidad no importa, pero para un archivo abierto probablemente sí.

En general, si algo tiene un método Dispose, debe llamar cuando haya terminado con él, o, si se puede, envolverlo en un comunicado using:

using (SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black)) 
{ 
    // use myBrush 
} 
0

Si es administrado (es decir, parte del marco) no necesita preocuparse por eso. Si implementa IDisposable simplemente envuélvalo en un bloque using.

Si desea utilizar recursos no administrados, debe leer los finalizadores e implementar IDisposable usted mismo.

Hay mucho más detalle en this question

0

Primero al finalizar el programa, puede suponer que la memoria utilizada por el proceso se eliminará con el proceso en sí.

Durante el uso de dispose o destructor en.net, se debe entender que el momento en que el GC llama a la función de eliminación es no determinista. Por eso, se recomienda utilizar el uso o la invocación explícita del recurso.

Al usar recursos como archivos, se deben liberar objetos de memoria como semaforos y recursos que viven fuera del mundo administrado de .net.

El SolidBrush por ejemplo, tiene que deshacerse de él porque es un objeto GDI y vive fuera del mundo .net.

0

El recolector de basura no solo se libera al finalizar el programa, de lo contrario no sería realmente útil (en cualquier SO decente/reciente, cuando el proceso finaliza, el sistema operativo limpia por completo su memoria).

Una de las grandes ventajas de C# en comparación con C/C++ es que no tiene que preocuparse por la liberación de objetos asignados (la mayoría de las veces al menos); el gc lo hace cuando el tiempo de ejecución decide (varias estrategias cuándo/cómo hacerlo).

Muchos Recursos no son atendidos por el GC: archivo, Recursos relacionados con los subprocesos (cerraduras), conexiones de red, etc ...

3

Las consecuencias de no disponer sus IDisposables pueden variar de un impacto de rendimiento insignificante a estrellar tu aplicación.

El objeto Pincel en su ejemplo será limpiado por el GC cuando así lo desee. Pero su programa no habrá tenido el beneficio de ese poco de memoria adicional que habría obtenido al limpiarlo antes. Si está utilizando muchos objetos Brush, esto puede volverse significativo. El GC también es más eficiente para limpiar objetos si no han estado por mucho tiempo, porque es un colector de basura generacional.

Por otro lado, las consecuencias de no eliminar los objetos de conexión de la base de datos podrían significar que se quede sin conexiones de bases de datos agrupadas muy rápidamente y que la aplicación se bloquee.

O bien utilizar

using (new DisposableThing... 
{ 
    ... 
} 

O, si necesita aferrarse a una referencia a un IDisposable en su objeto de su vida útil, implementar IDisposable en su objeto y llamar al método Dispose del IDisposable.

class MyClass : IDisposable 
{ 
    private IDisposable disposableThing; 

    public void DoStuffThatRequiresHavingAReferenceToDisposableThing() { ... } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) 
    //etc... (see IDisposable on msdn) 

}

0

Un lugar que tener cuidado es que los objetos parecen pequeño para GC, pero no son ... En la API de SharePoint, por ejemplo, el objeto SPWeb tiene un tamaño reducido en cuanto a la GC está preocupado y, por lo tanto, tendrá baja prioridad para la recopilación, pero realmente ha atrapado un montón de memoria (en el montón, creo) que el GC no conoce. Te encontrarás con algunos problemas divertidos de memoria si estás descubriendo un montón de estos, por ejemplo, ¡recuerda siempre utilizar o desechar!

1

Como han dicho otros, usar es tu amigo. Escribí this blog entry sobre cómo implementar IDisposable de una manera bastante directa que es menos propensa a errores al factorizar las partes que son las más importantes.

1

Un truco que utilizo cuando no puedo recordar si un objeto dado es un recurso desechable es escribir ".Dispose" (como máximo!) Después de la declaración para obtener Intellisense para comprobar por mí:

MemoryStream ms = new MemoryStream().Dispose 

continuación, elimine la .Dispose y utilizar el uso de) Directiva (:

using(MemoryStream ms = new MemoryStream()) 
{ 
    ... 
} 
+0

¡Tenga en cuenta que este truco no funcionará si Dispose se ha implementado explícitamente! –

0

en lugar de pensar de un objeto como "explotación" de recursos que deben ser puestos en libertad, es mejor pensar en términos de un objeto como tener alterado algo (¡posiblemente fuera de la computadora!) que sobrevivirá, de una manera co Puede ser dañino si no se deshace o se "limpia", pero solo el objeto puede limpiar. Si bien esta alteración comúnmente toma la forma de un objeto concreto en un grupo que se marca como "ocupado", su forma precisa no importa. Lo que importa es que los cambios deben deshacerse, y el objeto contiene la información necesaria para hacer eso.

Cuestiones relacionadas