¿Cómo funciona la recolección de basura en referencias de objetos?

Estoy confundido sobre el proceso de recolección de basura en los objetos.

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

Al llamar solo a la variable B dispuesta, el objeto creado no se recolectará como basura ya que el objeto aún tiene una referencia de A.

Ahora, ¿el siguiente código funciona igual que arriba?

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

Ahora llamo a esta función estática desde 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 llamar a Dispose on B, la conexión entre B y el objeto se pierde, pero lo que sucede con la referencia que se pasa desde Test1. ¿Permanecerá activo hasta que finalice el scope de la función TestB?

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

Puede que esté fuera, pero parece que tienes un malentendido sobre la Dispose basura y el desecho. Un objeto se recolectará como basura una vez que todas las referencias a él hayan desaparecido, de una manera no determinista. La disposición generalmente eliminará los recursos no administrados, por lo que el objeto está listo para ser recolectado como basura. En su primer ejemplo, eliminó el objeto, en teoría lo dejó inutilizable, pero aún existe en el montón y todavía tiene una referencia a él, tanto A como B. Una vez que quedan fuera del scope, el recolector de basura puede reclamar esa memoria. , pero no siempre. En el ejemplo 2, se coloca un bitmap A en el montón, luego devuelve una referencia y establece B para esa referencia. Luego lo dispones y B se sale del scope. En ese momento ya no hay más referencias a él, y se recogerá como basura en un momento posterior.

Dispose no recoger basura. No se puede recolectar explícitamente un objeto en particular. Puede llamar a GC.Collect() que solicita que se ejecute el recolector de basura, pero eso no es lo mismo. Llamar a Dispose ni siquiera “desconecta” el objeto de una variable en particular, de hecho … mientras esa variable permanece en vivo (hasta la última vez que el JIT puede detectar que se volverá a leer) evitará que el objeto siendo recogido basura.

Un objeto no se recogerá en la basura hasta que ya no esté referenciado por nada. Es cierto que esto puede ser anterior a lo que podría pensar en algunos casos extremos, pero rara vez debe preocuparse por eso.

Vale la pena tener en cuenta que la Dispose residuos y la basura son cosas muy diferentes. Usted llama a 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ía de las veces debería disponer de recursos no administrados explícitamente.

Sucede que Raymond Chen acaba de escribir una serie de publicaciones de blog que describen aspectos de la recolección de basura .NET. Esta publicación se relaciona más directamente con su pregunta (¿cuándo se recolectan objetos en la basura?).

Dispose () no tiene nada que ver con la recolección de basura. Todo lo que hace es permitir la liberación determinista de recursos, pero hay que llamarlo explícitamente. El objeto al que lo llama no se recolecta cuando llama a Dispose (). Será elegible para la recolección de basura cuando todas las referencias hayan desaparecido.

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

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

Con archivos, conexiones db, etc., a menudo desea cerrarlos lo antes posible para liberar recursos no administrados y evitar problemas de locking.

Con los tiradores de las ventanas tenemos una afinidad de hilos por la que preocuparnos. Como un GC se ejecuta en un subproceso dedicado, ese subproceso es siempre el subproceso incorrecto para liberar los identificadores de Windows.

Por lo tanto, GC ayuda mucho para evitar perder memoria administrada y reducir el desorden de código, pero uno aún debería liberar recursos no administrados lo antes posible.

el uso de () statement es una bendición.

PD. Muy a menudo implemento IDisposable aunque no tengo ningún recurso directo no administrado, aunque no importa para informar a todas las variables miembro que implementan IDisposable que se ha llamado a Disose.

Ok para empezar Dispose! = Garbage Collected. Puede llamar a desechar y nunca hacer que se recolecte la basura, ya que un “Objeto desechado” todavía puede tener referencias a él. El método de disposición se utiliza para “ordenar” el objeto antes de que se ejecute el CG (cierre las conexiones de base de datos abiertas o las conexiones de archivos, etc.).

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

En este caso, B.Dispose está llamando al método de disposición en A, porque B está haciendo referencia al objeto en la variable A. Ninguno será CGd, porque aún no han quedado fuera del scope.

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

Lo que sucede aquí es que está creando el objeto A y lo está devolviendo, de modo que cuando abandona la Prueba1, es muy probable que A otra variable haga referencia a A en el método de llamada. Esto significa que, aunque haya dejado el método, A todavía está enraizado (lo más probable) y no será CG’d hasta que el método de llamada haya terminado.

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

Aquí se está creando B y llamando a disponer. Esto no significa que se pueda recolectar. Una vez que el progtwig abandona el método, B queda fuera del scope, lo que significa que se puede recostackr la próxima vez que se llame al GC.

Cuando usar Dispose

Puede que valga la pena señalar que llamar a Dispose puede, de hecho, no hacer nada. Le da al objeto la oportunidad de limpiar recursos como conexiones de base 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 hora de limpiar esas referencias.

La pregunta fundamental en la recolección de basura es: “¿Se puede alcanzar este objeto?” Mientras haya un objeto en la stack 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á recolectado como basura.

Ejemplo:

ObjA crea un ObjB, que crea un ObjC. Obj C no se recogerá como basura hasta que ObjB ya no haga referencia a él, o hasta que ObjA ya no haga referencia a ObjB, o hasta que no haya objetos que conserven una referencia a ObjA.

Nuevamente, la pregunta que debe hacerse es: “¿Se puede hacer referencia a este objeto actualmente por algo en el código?”