2009-02-13 20 views
6

En el siguiente código C#, ¿cómo me deshago de los objetos cuando ya no es útil? ¿Se atiende automáticamente o necesito hacer algo?¿Cómo deshacerse de un objeto en C#

public void Test() 
{ 
    object MyObject = new object(); 

    ... code ... 
} 
+0

Disculpe la edición, solo trato de detener un problema antes de que comience inadvertidamente, sin ánimo de ofender. –

+0

Lol, y yo * así que * quería que alguien me dijera cómo eliminar esa variable * particular * –

+0

@lc Y, por supuesto, sin ofender :-) –

Respuesta

5

La respuesta corta es: a menos que tenga recursos no administrados (manejadores de archivos, etc.) no necesita preocuparse.

La respuesta larga es un poco más complicada.

Cuando .NET decide que quiere liberar algo de memoria, ejecuta el recolector de basura. Esto busca todos los objetos que todavía están en uso y los marca como tales. Cualquier variable local (en cualquier marco de pila de cualquier subproceso) que aún pueda leerse cuenta como raíz al igual que las variables estáticas.(De hecho, creo que las variables estáticas se referencian a través de objetos Type en vivo, que se referencian a través de objetos AppDomain en vivo, pero en su mayoría se pueden considerar variables estáticas como raíces.)

El recolector de basura observa cada objeto al que se hace referencia por una raíz, y luego encuentra más referencias "en vivo" basadas en las variables de instancia dentro de esos objetos. Se reactiva, buscando y marcando más y más objetos como "en vivo". Una vez que ha finalizado este proceso, puede examinar todos los objetos y liberarlos.

Eso es un muy amplio cuadro conceptual - pero se vuelve mucho más detallada cuando se piensa en el modelo generacional de recolección de basura, finalizadores, recolección concurrente etc. Recomiendo encarecidamente la lectura de CLR via C# Jeff Richter, que se dedica a esto en muchos detalles. También tiene un artículo twopart (desde 2000, pero sigue siendo muy relevante) si no desea comprar el libro.

Por supuesto, todo esto no significa que no tenga que preocuparse por el uso de memoria y la duración de los objetos en .NET. En particular:

  • Creación de objetos sin sentido se funcionamiento de coste. En particular, el recolector de basura es rápido pero no gratuito. Busque simple formas de reducir el uso de memoria a medida que codifica, pero la optimización microscópica antes de saber que tiene un problema también es mala.
  • Es posible "perder" la memoria al hacer que los objetos se puedan alcanzar por más tiempo del que se esperaba. Dos causas razonablemente comunes de esto son las variables estáticas y las suscripciones a eventos. (Una suscripción de evento hace que el manejador de eventos sea accesible desde el publicador del evento, pero no al revés.)
  • Si usa más memoria (en vivo, accesible) de la que tiene disponible, su aplicación se bloqueará. No hay mucho que .NET pueda hacer para prevenir eso.
  • Los objetos que utilizan recursos que no son de memoria suelen implementar IDisposable. Debe llamar al Dispose para liberar esos recursos cuando haya terminado con el objeto. Tenga en cuenta que este no libera el objeto, solo el recolector de basura puede hacerlo. La declaración using en C# es la manera más conveniente de llamar al Dispose de manera confiable, incluso ante una excepción.
18

Automatically. Cuando MyObject queda fuera del alcance (al final de la prueba), se marca para la recolección de elementos no utilizados. En algún momento en el futuro, el tiempo de ejecución .NET va a limpiar la memoria para que

Editar: (Debo señalar en aras de la exhaustividad que si pasa MiObjeto en alguna parte, que se pasa por referencia, y no se recoja basura: solo cuando no hay más referencias al objeto flotando, el GC puede recogerlo libremente)

Editar: en una compilación de lanzamiento, MyObject generalmente se recogerá tan pronto como no se use (ver mi respuesta para obtener más detalles --dp)

+0

Esta respuesta hace que todo el proceso suene más activo de lo que es. Nada "marca" el objeto cuando sale del alcance; simplemente no cuenta cuando el GC intenta encontrar objetos * no * para tirar. –

+0

Ah, y MyObject solo se pasa por referencia usando "ref". De lo contrario, se pasa por valor, pero el valor * es * una referencia. No son lo mismo. –

+0

Con respecto a la edición de dp, ser * elegible * para GC anticipadamente no es lo mismo que "generalmente se recopilará tan pronto como no se use": aún debe esperar a que el GC realice una recopilación. –

3

En código optimizado, es posible y probable que MyObject se recopile antes de que finalice el método. De forma predeterminada, la configuración de depuración en Visual Studio se compilará con el interruptor de depuración y el apagado optimizado, lo que significa que MyObject se mantendrá hasta el final del método (para que pueda ver el valor durante la depuración). Construir con optimización desactivada (la depuración no importa en este caso) permite que MyObject se recopile después de que se determine que no se utiliza. Una forma de forzarlo a mantenerse activo hasta el final del método es llamar a GC.KeepAlive (MyObject) al final del método.

4

Las otras respuestas son correctas, a menos que su objeto es una instancia de una clase que implementa la interfaz IDisposable, en cuyo caso se debe (explícitamente, o implícitamente a través de un comunicado using) llama el método del objeto Dispose.

1

Normalmente, la recolección de basura puede depender de la limpieza, pero si su objeto contiene recursos no administrados (conexiones de bases de datos, archivos abiertos, etc.) deberá cerrar explícitamente esos recursos y/o exceder el método de eliminación en el objeto (si implementa IDisposable). Esto puede provocar errores, por lo que debe tener cuidado con la forma de tratar este tipo de objetos. Simplemente cerrar un archivo después de usarlo no siempre es suficiente, ya que una excepción antes de que se ejecute el cierre dejará el archivo abierto. O use un bloque de uso o un bloque de intento final.

En pocas palabras: "usar" es tu amigo.

2

Esto forzará al recolector de basura a deshacerse de los objetos no utilizados.

GC.Collect(); 
GC.WaitForPendingFinalizers(); 

Si desea que se recoja un objeto específico.

object A = new Object(); 
... 
A = null; 
GC.collect(); 
GC.WaitForPendingFinalizers(); 
+1

No es necesario establecerlo en nulo si es una variable local y no se usa en el resto del método. (Suponiendo que se está ejecutando en modo de lanzamiento). –

Cuestiones relacionadas