2012-01-12 17 views
47

Considere estas dos clases:colector de basura y la referencia circular

public class A 
{ 
    B b; 
    public A(B b) { this.b = b; } 
} 

public class B 
{ 
    A a; 
    public B() { this.a = new A(this); } 
} 

Si he clases diseñada como la de arriba, serían los objetos de dichas clases serán recogidos por recolector de basura (GC)?

Supongamos que hago esto:

void f() 
{ 
    B b = new B(); 
} 

En este método, se crea una instancia de B llamada b, y cuando el método retorna, b sale del ámbito y el GC debería ser capaz de recogerlo , pero si se tratara de recopilarlo, primero tendría que recopilar a, que es el miembro de B, y para recopilar a, primero debe recopilar b, que es el miembro de A. Se vuelve circular. Entonces mi pregunta es: ¿tal referencia circular va a evitar que GC recolecte los objetos?

  • En caso afirmativo, ¿cómo podemos evitar este problema? ¿Cómo podemos asegurarnos de que no tengamos referencias circulares en nuestro diseño de clase? ¿Hay alguna herramienta (o opción de compilación) que nos ayude a detectar referencias circulares?
  • En caso negativo, ¿dónde y por qué usamos la clase WeakReference? ¿Cual es su propósito?
+1

Eche un vistazo aquí http://stackoverflow.com/questions/400706/circular-references-cause-memory-leak –

+0

Al menos lógicamente una de las referencias siempre será débil: en su ejemplo, cleary 'A 'no puede depender de' B', porque 'A' debe hacerse primero, como miembro de' B', y 'A' solo puede contener una referencia débil a' B'. Por lo tanto, es seguro destruir 'B' primero y luego' A'. Argumentando recursivamente, cada programa de computadora debe ser así. Nunca puede haber una dependencia circular * verdadera *, totalmente simétrica. –

+0

@KerrekSB: Estoy de acuerdo con esa lógica. Pero eso se ve desde el punto de la creación. ¿El GC va a analizar esto (es decir, el código en cada método de tales clases, después de todo, solo entonces puede llegar a esa conclusión)? Quiero decir, si ves los objetos después de que han sido creados, entonces parece muy problemático. – Nawaz

Respuesta

74

El recolector de basura .Net puede manejar absolutamente referencias circulares. La vista de alto nivel muy de cómo funciona el recolector de basura es ...

  • de inicio con los locales, la estática y objetos GC fijado. Ninguno de estos puede recopilarse
  • Marcar todos los objetos que se pueden alcanzar al atravesar los elementos secundarios de estos objetos
  • Recoger todos los objetos que no estén marcados.

Esto permite que las referencias circulares se recopilen muy bien. Siempre que ninguno de ellos sea accesible desde un objeto que se sabe que no se puede recoger, entonces la referencia circular es esencialmente irrelevante.

Nota: Me doy cuenta que he dejado fuera muchos detalles de la diversión con el fin de mantener esta respuesta simple y directa

+0

¿No sería eso costoso computacionalmente? –

25

No, esto no será un problema porque GC puede manejar referencias circulares

MSDN Says

Si un grupo de objetos contienen referencias a unos de otros, pero ninguno de estos objetos se hace referencia directa o indirectamente de la pila o variables compartidas, entonces la recolección de basura recuperará automáticamente la memoria.

+1

¡Y eso es lo que hace que este lenguaje sea genial! – Aggressor

5

Sin esa referencia circular no afectará el recolector de basura, y será perfectamente capaz de recoger la instancia de B.

El recolector de basura sabe que nadie puede hacer referencia a la instancia de B después de ir fuera del alcance, y en consecuencia, nadie puede usar la instancia de B para hacer referencia indirectamente a A.

5

Varias respuestas ya se ha explicado que las referencias circulares no son un problema.

En cuanto a las referencias débiles, la razón para usarlas es el almacenamiento en caché.

Cuando GC recorre árboles de dependencia de objetos, ignora las referencias débiles. En otras palabras, si la única referencia a un objeto es débil (s), será basura recolectada, pero si no hubo recolección de basura entre la creación de referencia y su intento de usar, aún puede acceder al objeto.

Cuestiones relacionadas