¿Recursos que deben limpiarse manualmente en C#?
limpiar variables en c++ (14)
¿Qué recursos deben limpiarse manualmente en C # y cuáles son las consecuencias de no hacerlo?
Por ejemplo, digamos que tengo el siguiente código:
myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black);
// Use Brush
Si no limpio el pincel utilizando el método de eliminación, supongo que el recolector de basura libera la memoria utilizada al finalizar el programa. ¿Es esto correcto?
¿Qué otros recursos necesito para limpiar manualmente?
Bueno, siempre que use la versión administrada de los recursos y no llame a las API de Windows usted mismo, 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.
Como otros han dicho, usar es tu amigo. Escribí esta entrada de blog sobre cómo implementar IDisposable de una manera bastante directa que es menos propensa a errores al factorizar las partes que son más importantes.
El recolector de basura manejará todos los recursos administrados. En su ejemplo, el cepillo se limpiará cuando el recolector de basura decida hacerlo, lo que ocurrirá un tiempo después de que la última referencia al cepillo ya no sea válida.
Hay ciertas cosas que necesitan ser limpiadas manualmente, pero esas son punteros recuperados de fuentes no administradas, como llamadas a DLL, sin embargo, nada dentro de .NET Framework necesita este tratamiento.
El recolector de basura no solo se libera al finalizar el programa, de lo contrario no sería realmente útil (en cualquier sistema operativo decente / reciente, cuando el proceso finaliza, el sistema operativo limpia toda su memoria de todos modos).
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 gc: file, recursos relacionados con hilos (bloqueos), conexiones de red, etc.
En general, cualquier cosa que implemente un 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á.
Las consecuencias de no eliminar sus Idisposables pueden variar desde un impacto de rendimiento insignificante hasta el bloqueo de su 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 deshacerse de 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 su aplicación falle.
Ya sea uso
using (new DisposableThing...
{
...
}
O bien, si necesita aferrarse a una referencia a un IDisposable en su objeto durante su vida útil, implemente IDisposable en su objeto y llame al método Dispose de 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)
}
Primero al finalizar el programa, puede suponer que la memoria utilizada por el proceso se eliminará con el proceso en sí.
Al usar dispose o destructor in.net, uno debe comprender 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 semafóricos y recursos que viven fuera del mundo administrado de .net.
El SolidBrush, por ejemplo, debe deshacerse porque es un objeto GDI y vive fuera del mundo .net.
Si no dispone de algo, se limpiará cuando el recolector de basura advierta que no hay más referencias a él 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 de eliminación, debe llamarlo cuando haya terminado con él o, si puede, envolverlo en una declaración de using
:
using (SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black))
{
// use myBrush
}
Técnicamente, todo lo que hereda de IDisposable debe eliminarse proactivamente. Puede usar la declaración ''using'' para facilitar las cosas.
http://msdn.microsoft.com/en-us/library/yh598w02.aspx
Algunas veces verá un uso inconsistente de los objetos derivados identificables en el código de muestra de la documentación, así como el código generado por las herramientas (es decir, el estudio visual).
Lo bueno de IDisposable es que le da la capacidad de liberar proactivamente el recurso subyacente no administrado. A veces, realmente quieres hacer esto: piensa en las conexiones de red y en los recursos de archivos, por ejemplo.
Un lugar para tener cuidado es el de Objetos que parecen pequeños para GC, pero no lo son ... En la API de SharePoint, por ejemplo, el objeto SPWeb tiene una huella pequeña en lo que respecta al GC, por lo que tendrá baja prioridad para la recopilación, pero realmente ha tomado 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 eliminar!
Un truco que uso cuando no puedo recordar si un determinado objeto es un recurso desechable es escribir ".Dispose" (¡como máximo!) Después de la declaración para que Intellisense compruebe:
MemoryStream ms = new MemoryStream().Dispose
A continuación, elimine el .Deseñe y use la directiva using ():
using(MemoryStream ms = new MemoryStream())
{
...
}
- Se encarga de las estructuras internas de datos de Windows.
- Conexiones a la base de datos
- File maneja.
- Conexiones de red.
- Referencias COM / OLE.
La lista continua.
Es importante llamar a Dispose
o, aún mejor, utilizar el patrón de using
.
using (SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black))
{
// use myBrush
}
Si no dispone de algo, se limpiará cuando el recolector de basura advierta que no hay más referencias al mismo, lo que puede ocurrir después de un 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 identificador.
En lugar de pensar en un objeto como "retener" recursos que necesitan ser liberados, es mejor pensar en términos de que un objeto ha alterado algo (¡posiblemente fuera de la computadora!) Que sobrevivirá, de alguna manera podría ser dañino si no deshecho o "limpiado", pero que 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.
Si se administra (es decir, parte del marco), no necesita preocuparse por ello. Si implementa IDisposable simplemente envuélvalo en un bloque de using
.
Si desea utilizar recursos no administrados, debe leer los finalizadores e implementar IDisposable usted mismo.
Hay muchos más detalles bajo esta pregunta