Recolector de basura y referencia circular

Considera estas dos clases:

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 tengo clases diseñadas como las anteriores, ¿Garbage Collector (GC) recogería los objetos de dichas clases?

Supongamos que hago esto:

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

En este método, creo una instancia de B llamada b , y cuando el método retorna, b sale del scope, y el GC debería ser capaz de recostackrlo, pero si fuera a recostackrlo, tendría que recostackr a primera que es el miembro de B , y para recolectar a , primero tiene que juntar 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?

  • Si es así, ¿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 comstackción) que nos ayude a detectar referencias circulares?
  • Si no, ¿dónde y por qué usamos la clase WeakReference ? ¿Cual es su propósito?

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

  • Comience con locales, estática y objetos fijados GC. Ninguno de estos puede ser recolectado
  • Marque cada objeto que se puede alcanzar al atravesar a los niños de estos objetos
  • Recoge 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 de que he omitido muchos detalles divertidos para mantener esta respuesta simple y directa

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

MSDN dice

Si un grupo de objetos contiene referencias el uno al otro, pero ninguno de estos objetos se referencia directa o indirectamente desde la stack o las variables compartidas, la recolección de basura recuperará automáticamente la memoria.

No, esa referencia circular no afectará al recolector de basura, y será perfectamente capaz de recolectar la instancia de B.

El recolector de basura sabe que nadie puede hacer referencia a la instancia de B después de salir del scope, y en consecuencia, nadie puede usar la instancia de B para hacer referencia indirecta a A.

Varias respuestas ya explicaron 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 bash de usar, aún puede acceder al objeto.