2009-12-31 120 views
24

Soy bastante nuevo para aprender C# (de Java & fondo C++) y tengo una pregunta sobre la eliminación manual de basura: ¿es posible destruir manualmente un objeto en C#? Sé sobre la interfaz IDisposable, pero supongamos que estoy tratando con una clase que no escribí y que no la implementa. No tendría un método .Dispose(), por lo que using { } está desactivado, y .Finalize siempre es protected o private, por lo que tampoco es una opción.Destruir manualmente objetos C#

(Estoy tratando de aprender lo que es posible en C# en este caso. Supongo que si todo lo demás falla que pudiera heredar la hipotética clase ImNotDisposable para que no implementar IDisposable.)

+3

Quizás debería aclarar la pregunta: ¿Desea desasignar un objeto por completo o simplemente forzar su método destructor para ejecutar y limpiar los recursos del objeto (únicamente)? –

+0

Supuse que uno implicaba al otro, pero lo que tenía en mente era alguna forma de "activar" el método ~ ClassName() que tiene un objeto. –

+0

Para resumir, GC tiene el método Collect() que es prácticamente todo o nada, y no hay forma de apuntar a un objeto específico. Gotcha. :) –

Respuesta

24

No destruye manualmente los objetos .Net. De eso se trata el ser un entorno administrado.

Lo que puede hacer es llamar al GC.Collect() para forzar una recopilación general. Sin embargo, casi nunca es una buena idea y no puedes hacer que se dirija a tu objeto específico. De hecho, si todavía tiene una referencia a este objeto que podría usar para indicarle a qué objeto desea apostar, le puedo prometer que no se recogerá.

En su lugar, probablemente sea mejor simplemente pretender que cualquier objeto que no utiliza recursos no administrados y no puede ser alcanzado por ningún otro objeto en su programa se destruye inmediatamente. Sé que esto no sucede, pero en este momento el objeto es solo un bloque de memoria como cualquier otro. No puede reclamarlo y eventualmente será recogido, por lo que puede ser que esté muerto para usted.

Una última nota sobre IDisposable. Sólo se debe utilizar para los tipos no administrados que envuelven recursos: cosas como enchufes, conexiones de bases de datos, objetos GDI, etc.

+4

También uso dispose para desvincular cualquier evento que haya conectado a objetos externos. Si no lo hace, el objeto no se eliminará de la memoria hasta que esté el objeto externo, lo que podría ser durante el tiempo de vida de la aplicación. –

+1

@MongusPong: 'Dispose' es muy importante, pero no" destruye "objetos, sino que les notifica que sus servicios ya no son necesarios, de modo que otras entidades (actuando en su nombre (si existen) pueden ser se notifica a su vez que * sus * servicios ya no son necesarios. – supercat

+0

Estoy totalmente en desacuerdo con la afirmación general "Solo debe usarla para tipos que envuelven recursos no administrados". Sé que es sabiduría convencional, pero si se ejecuta en problemas de pérdida de memoria , es muy bueno dejar los artículos desechables. La razón es que las aplicaciones de buen seguimiento de memoria podrán mostrarle los objetos que han sido desechados, pero que aún no han sido destruidos. Muestra claramente lo que ha marcado para la destrucción, pero no lo ha hecho ha sido destruido. Además de eso, le ofrece una buena oportunidad, y un lugar estándar para desenganchar manejadores de eventos, y así sucesivamente, para que la malla se rompa correctamente. –

6

Si el objeto no es alcanzable, puede llamar al GC.Collect() y el objeto será destruido. El concepto de IDisposable no tiene nada que ver con el CLR y es principalmente para que el código de usuario implemente para realizar la lógica de eliminación adicional. Llamar a Dispose() en un objeto no liberará el objeto de la memoria, aunque puede disponer de los recursos a los que este objeto hace referencia.

debo añadir que, si bien lo que he dicho es una manera de lograr esto, en un 99,9999% de las solicitudes nunca se debe llamar GC.Collect() porque va a menudo degradan el rendimiento de la aplicación en lugar de mejorarla.

+3

llamando a 'GC.Collect()' no es algo que deba hacer, a menos que sea por una * muy * buena razón. –

+0

para agregar a esto, solo recogerá el objeto si no hay más referencias a ese objeto. – McAden

+1

No se trata de referencias al objeto, se trata de accesibilidad (que sí menciono). – Eilon

5

No, no puedes destruir un objeto específico.

Es posible invocar el recolector de basura, que buscará objetos para destruir, pero casi nunca es una buena idea.

3

Usted puede forzar el recolector de basura para funcionar después de la variable que desea destruir sale de alcance, pero normalmente no desea hacer eso, ya que el recolector de basura es más eficiente si se deja hacer su propio trabajo.

Forzando la recolección de basura se puede hacer con GC.Collect, pero no lo hagas. En mis 10 años como desarrollador .NET, nunca lo he necesitado.

1

No es posible destruir un objeto de forma determinista. CLR determina cuándo se reclama el objeto marcado. Esto significa que, si bien puede marcar un objeto para reclamar y garantizar que los recursos administrados y no administrados se arreglen para su eliminación (mediante la implementación del patrón IDisposable), el tiempo real de liberación de la memoria depende del CLR. Esto es diferente de C++, donde podrías eliminar algo y luego se lanzaría.

codificación feliz,

de Scott

+1

Llamar a disponer no marca el objeto como Clamable, solo le permite liberar recursos limitados, como conexiones de bases de datos, tan pronto como haya terminado con ellos en lugar de esperar a que el recolector de basura venga y decida que es hora de finalizar el objeto. – Paolo

1

Usted no puede destruir manualmente un objeto "como C++ borrar", todo lo que puede hacer es simplemente cerrar los recursos exclusivos del objeto ha adquirido y nulos los referencias a este objeto, para que el GC pueda recopilarlo, tampoco llame a GC.Collect() usted mismo, el proceso de GC es costoso, ya que tiene que suspender todos los otros hilos para recolectar los objetos de manera segura de la memoria, así que solo confíe el GC, y comenzará cuando sea necesario.

+3

Bueno, en realidad nunca asignaría ninguna variable de referencia a un valor nulo como myObj = null; Solo les permitiría salir del alcance. –

+1

Acepto, prefiero intentar hacer esto si es posible – bashmohandes

6

Aunque puede desencadenar la recolección de elementos no utilizados (debe activar GC para todas las generaciones porque no puede estar seguro de en qué generación está el objeto finalizable) no puede forzar necesariamente la finalización de un objeto en particular. Solo puede confiar en las suposiciones sobre cómo funciona el recolector de basura.

Furtnermore, dado que la finalización ocurre en su propio hilo, debe llamar al WaitForPendingFinalizers después de activar la recolección de basura.

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

Como se señaló por otros, en realidad esto puede perjudicar el rendimiento de su aplicación, ya que innecesariamente invocando la GC puede promover objetos de otra forma de vida corta en las generaciones mayores que son más caros para recoger y se recogen con menos frecuencia.

En general, una clase que implementa un finalizador (destructor) y no implementa IDisposable está mal visto. Y todo lo que implemente IDisposable debería llamarlo lógica de finalizador y suprimirse de la finalización en la recolección de basura.

Jeff Richter recientemente publicó un pequeño truco para receiving a notification when garbage collection occurs.

Otro gran artículo sobre Garbage Collector Basics and Performance Hints de Rico Mariani (MSFT)

0

Digamos que tiene una matriz de clase y que ha creado dos objetos matriz Amatrix y bmatrix. En C#, puede destruir (finalizar) manualmente un objeto como el siguiente:

aMatrix = NULL;

GC.Collect();

El recolector de basura notará que su aMatrix es NULL y la destruirá (finalizará). Si esta es una buena idea o no, es una historia diferente.