2010-08-13 7 views
9

Estoy confundido sobre el proceso de recolección de basura en los objetos.¿Cómo funciona la recolección de basura en las referencias de objetos?

object A = new object(); 
object B = A;   
B.Dispose(); 

de prepago de una Dispose en la variable B solamente, el objeto creado no será basura recogida que el objeto está todavía ha referenciado por A.

Ahora hace lo siguiente código funcione igual que el anterior?

public static image Test1() 
{ 
    Bitmap A = new Bitmap(); 
    return A; 
} 

Ahora llamo a esta función estática de algún otro método.

public void TestB() 
{ 
    Bitmap B = Test1(); 
    B.Dispose(); 
} 

La función estática Test1 devolvió una referencia al objeto Bitmap. La referencia se guarda en otra variable B. Al invocar un Dispose on B, la conexión entre B y el objeto se pierde, pero lo que ocurre con la referencia que se pasa desde Test1. ¿Permanecerá activo hasta que se complete el alcance de la función TestB?

¿Hay alguna manera de eliminar inmediatamente la referencia que se pasa de la función estática?

+2

basura la colección no es un conteo de referencias. –

+0

El objetivo de la recolección de basura es que no tiene que preocuparse de cuándo o si se está liberando la memoria. En principio, en un sistema con grandes reservas de memoria, la recolección de basura nunca podría suceder, simplemente porque sería más eficiente simplemente dejar que todo se limpie cuando la aplicación finalice. –

Respuesta

15

Puedo estar apagado, pero parece que tiene un malentendido de Dispose y recolección de basura. Un objeto será basura recolectada una vez que todas las referencias hayan desaparecido, de una manera no determinista. Dispose generalmente eliminará los recursos no administrados, por lo que el objeto estará listo para ser recolectado. En su primer ejemplo, eliminó el objeto, lo que lo hace teóricamente inutilizable, pero todavía existe en el montón y todavía tiene una referencia al mismo, tanto A como B. Una vez que estos salgan del alcance, el recolector de basura puede reclamar esa memoria , pero no siempre. En el ejemplo 2, se coloca un mapa de bits A en el montón, luego se devuelve una referencia y se establece B en esa referencia. Luego lo descarta y B sale del alcance. En ese momento, ya no existen más referencias, y se recolectará basura en un momento posterior.

+0

Gracias por su respuesta. Debería haber dejado mi pregunta más clara. Soy consciente de que al llamar a Dispose(), GC no liberará la memoria inmediatamente, pero eliminará la referencia al objeto de la cola finalizable para que el objeto no se mueva a la siguiente generación. En el segundo ejemplo, ¿cómo llamamos a disponer? en la referencia aprobada por la función inmediatamente después del uso? Si no podemos eliminar la referencia aprobada por la función estática, se moverá a la próxima generación y habrá más retraso para liberar el recurso. – kishore

+1

@kishore: Cuando dices disponer de la referencia, es muy confuso lo que quieres decir. La referencia es un puntero en la pila al objeto en el montón, al menos en este caso. Usted descarta los recursos no administrados en la instancia en el montón. –

+0

Perdón por la confusión. Entonces, ¿hay alguna manera de eliminar o borrar la referencia que pasa la función para que no apunte al objeto en el montón? – kishore

15

Dispose hace no basura recoger. No se puede recoger basura de manera explícita un objeto en particular. Puede llamar al GC.Collect() que solicita que el recolector de basura ejecuta, pero eso no es lo mismo. Llamar al Dispose ni siquiera "desconecta" el objeto de una variable particular, de hecho ... mientras esa variable permanezca activa (hasta la última vez que el JIT puede detectar que alguna vez volverá a leerse) evitará que el objeto siendo basura recolectada.

Un objeto no será basura recolectada hasta que ya no se haga referencia a nada. Es cierto que esto puede ser más temprano de lo que podría pensar en algunos casos extremos, pero rara vez tiene que preocuparse por eso.

Vale la pena tener en cuenta que Dispose y la recolección de basura son cosas muy diferentes. Llame al Dispose para liberar recursos no administrados (conexiones de red, etc.). La recolección de basura es únicamente para liberar memoria. Es cierto que la recolección de basura puede pasar por una finalización que puede liberar recursos no administrados como último recurso, pero la mayor parte del tiempo debe deshacerse de recursos no administrados de manera explícita.

+0

Como una adición, debe * nunca * confiar en los finalizadores, ya que es posible que nunca se ejecuten. En el mejor de los casos, pueden ser los "últimos centros turísticos" que tratarán de limpiar los recursos si el programa olvidó deshacerse de ellos de manera adecuada. – siride

3

Dispose() no tiene nada que ver con la recolección de basura. Todo lo que hace es permitir la liberación determinística de recursos, pero debe llamarlo de manera explícita. El objeto al que lo llamas no obtiene basura recolectada cuando llamas a Dispose(). Será elegible para la recolección de basura cuando todas las referencias hayan desaparecido.

5

Ocurre que Raymond Chen acaba de escribir una serie de publicaciones en el blog que describen aspectos de la recolección de basura .NET. This post se relaciona más directamente con su pregunta (¿cuándo se recogen los objetos?).

+0

Espero con ansias CLR semana todos los años :) –

+0

Iba a publicar un enlace, pero me sentía un poco vago esta mañana. Ha tenido excelentes publicaciones sobre temas relacionados con GC. – siride

+0

Gracias por compartir la publicación. – kishore

1

Ok para principiantes Eliminar = Basura recolectada. Puede llamar a disponer y nunca tenerlo Recogido basura, porque un "Objeto expuesto" aún puede tener referencias a él. El método de eliminación se utiliza para "poner en orden" el objeto antes de que se ejecute el CG (cerrar conexiones abiertas de BD, o conexiones de archivos, etc.).

object A = new object(); 
object B = A;   
B.Dispose(); 

En este caso B.Dispose está llamando al método Dispose en A, B, porque hace referencia al objeto en la variable A. Tampoco será CGD, porque no han caído fuera de alcance todavía.

public static image Test1() 
{ 
    Bitmap A = new Bitmap(); 
    return A; 
} 

Lo que ocurre aquí es que va a crear un objeto y devolverlo, por lo que cuando salga Prueba1, A es más probable que se hace referencia por otra variable en el método de llamada. Esto significa que, aunque haya abandonado el método, A aún está enraizado (lo más probable) y no será procesado por CG hasta que el método de llamada finalice.

public void TestB() 
{ 
    Bitmap B = Test1(); 
    B.Dispose(); 
} 

Aquí B se está creando y llamando a deshacerse de. Esto no quiere decir que será coleccionable. Una vez que el programa abandona el método, B queda fuera del alcance, lo que significa que se puede recopilar la próxima vez que se llame al GC.

When to use Dispose

2

Muchas buenas respuestas aquí, pero también me gustaría señalar que la razón por la que la gente pensaba que necesitaba IDisposable es que un GC en realidad debería llamarse MemoryCollector o incluso ManagedMemoryCollector. Un GC no es especialmente inteligente cuando se trata de recopilar recursos de memoria no administrados, como archivos, conexiones de DB, transacciones, identificadores de ventanas, etc.

Una de las razones es que un objeto administrado puede tener un recurso no administrado que requiere varios gigas de RAM, pero para el GC parece aproximadamente 8 bytes.

Con archivos, db conns y demás, a menudo desea cerrarlos lo antes posible para liberar recursos no administrados y evitar problemas de bloqueo.

Con las manijas de las ventanas tenemos afinidad con los hilos por los que preocuparnos. Como un GC se ejecuta en un hilo dedicado, ese hilo siempre es el hilo equivocado para liberar manejadores de ventanas.

Por lo tanto, GC ayuda mucho a evitar la fuga de la memoria administrada y reducir el desorden del código, pero aún se deben liberar los recursos no administrados lo antes posible.

usando() la declaración es una bendición.

PS. Muy a menudo implemento IDisposable aunque no tengo ningún recurso directo no administrado, aunque no importa si informa todas las variables miembro que implementan IDisposable que se ha llamado a Dispose.

0

Vale la pena señalar que llamar a Dispose puede, de hecho, no hacer nada en absoluto. Le da al objeto la oportunidad de limpiar recursos como conexiones de bases de datos y recursos no administrados. Si tiene un objeto que contiene un recurso no administrado, como una conexión de base de datos, Dispose le dirá al objeto que es el momento de limpiar esas referencias.

La pregunta fundamental en la recolección de basura es: "¿Se puede alcanzar este objeto?"Siempre que haya un objeto en la pila que tenga una referencia a su objeto (o haya una referencia a este objeto en algún lugar de la jerarquía de objetos), el objeto no será basura.

Ejemplo:

ObjA crea un ObjB, que crea un Obj C. Obj C no se recolectará como basura hasta que ya no se haga referencia a ObjB, o hasta que ObjB ya no esté referenciado por ObjA, o hasta que no haya objetos que retengan una referencia ObjA.

de nuevo, la pregunta es: "¿puede este objeto actualmente ser referenciado por nada en el código?"

+0

También debería haber mencionado que, solo porque un objeto no esté referenciado, no significa que se recopilará inmediatamente. El recolector de basura toma decisiones basadas en cuánto tiempo estuvo vivo un objeto, cuánta memoria consume y la presión de la memoria en el sistema para determinar qué recolectar y cuándo. Eso requiere un poco más de comprensión del recolector de basura en su sistema para optimizar realmente el uso de la memoria. Pero para un principiante en GC, es seguro asumir que la memoria es propiedad del recolector de basura una vez que el objeto ya no se puede alcanzar. – Jason

+0

-1 porque esta publicación confunde GC y el propósito de Dispose(). Es cierto que Dispose() está ahí para limpiar recursos no administrados. Pero su código lo llama determinista y explícitamente. Nunca será llamado por el recolector de basura y llamar a Dispose() nunca resultará en que el objeto sea recolectado. – siride

Cuestiones relacionadas