Según tengo entendido, la recolección de basura en Java limpia algunos objetos si nada más está 'apuntando' a ese objeto.
Mi pregunta es, qué pasa si tenemos algo como esto:
class Node {
public object value;
public Node next;
public Node(object o, Node n) { value = 0; next = n;}
}
//...some code
{
Node a = new Node("a", null),
b = new Node("b", a),
c = new Node("c", b);
a.next = c;
} //end of scope
//...other code
a
, b
Y c
debe ser recogido de basura, pero todos ellos están siendo referenciado por otros objetos.
¿Cómo trata la recolección de basura Java con esto? (¿o es simplemente una pérdida de memoria?)
java
garbage-collection
AlexeyMK
fuente
fuente
Respuestas:
El GC de Java considera que los objetos son "basura" si no son accesibles a través de una cadena que comienza en una raíz de recolección de basura, por lo que estos objetos serán recolectados. Aunque los objetos pueden señalarse entre sí para formar un ciclo, siguen siendo basura si están separados de la raíz.
Consulte la sección sobre objetos inalcanzables en el Apéndice A: La verdad sobre la recolección de basura en el rendimiento de la plataforma Java: estrategias y tácticas para obtener detalles sangrientos.
fuente
sí ¡El recolector de basura Java maneja la referencia circular!
Hay objetos especiales llamados raíces de recolección de basura (raíces GC). Estos son siempre accesibles y también lo es cualquier objeto que los tenga en su propia raíz.
Una aplicación Java simple tiene las siguientes raíces GC:
Para determinar qué objetos ya no están en uso, la JVM ejecuta de manera intermitente lo que se llama muy bien un algoritmo de marcado y barrido . Funciona de la siguiente manera
Por lo tanto, si no se puede acceder a ningún objeto desde las raíces del GC (incluso si es autorreferenciado o cíclico), estará sujeto a la recolección de basura.
Por supuesto, a veces esto puede conducir a una pérdida de memoria si el programador olvida desreferenciar un objeto.
Fuente: Java Memory Management
fuente
Un recolector de basura comienza desde algún conjunto "raíz" de lugares que siempre se consideran "accesibles", como los registros de la CPU, la pila y las variables globales. Funciona encontrando cualquier puntero en esas áreas, y encontrando recursivamente todo lo que señalan. Una vez que se encuentra todo eso, todo lo demás es basura.
Hay, por supuesto, bastantes variaciones, principalmente por el bien de la velocidad. Por ejemplo, la mayoría de los recolectores de basura modernos son "generacionales", lo que significa que dividen los objetos en generaciones, y a medida que un objeto envejece, el recolector de basura se alarga cada vez más entre las veces que intenta averiguar si ese objeto aún es válido o no. - Simplemente comienza a suponer que si ha vivido mucho tiempo, es muy probable que continúe viviendo aún más.
No obstante, la idea básica sigue siendo la misma: todo se basa en comenzar a partir de un conjunto raíz de cosas que da por sentado que aún se podrían usar, y luego perseguir todos los punteros para encontrar qué más podría estar en uso.
Interesante aparte: muchas personas pueden sorprenderse a menudo por el grado de similitud entre esta parte de un recolector de basura y el código para ordenar objetos para cosas como llamadas a procedimientos remotos. En cada caso, está comenzando desde algún conjunto raíz de objetos y persiguiendo punteros para encontrar todos los otros objetos a los que se refieren ...
fuente
Estás en lo correcto. La forma específica de recolección de basura que describe se denomina " recuento de referencias ". La forma en que funciona (conceptualmente, al menos, las implementaciones más modernas de conteo de referencias se implementan de manera bastante diferente) en el caso más simple, se ve así:
Y esta estrategia simple tiene exactamente el problema que usted describe: si A hace referencia a B y B hace referencia a A, entonces sus dos recuentos de referencia nunca pueden ser inferiores a 1, lo que significa que nunca se recopilarán.
Hay cuatro formas de lidiar con este problema:
Por cierto, la otra forma importante de implementar un recolector de basura (y ya lo he insinuado un par de veces más arriba) es el rastreo . Un colector de rastreo se basa en el concepto de accesibilidad . Comienza con un conjunto raíz que sabe que siempre es accesible (constantes globales, por ejemplo, o la
Object
clase, el alcance léxico actual, el marco de pila actual) y desde allí rastrea todos los objetos a los que se puede acceder desde el conjunto raíz, luego todos los objetos a los que se puede acceder desde los objetos accesibles desde el conjunto raíz y así sucesivamente, hasta que tenga el cierre transitivo. Todo lo que no está en ese cierre es basura.Como un ciclo solo es accesible dentro de sí mismo, pero no es accesible desde el conjunto raíz, se recopilará.
fuente
Los GC de Java en realidad no se comportan como usted describe. Es más exacto decir que comienzan a partir de un conjunto base de objetos, frecuentemente llamados "raíces GC", y recolectarán cualquier objeto que no pueda ser alcanzado desde una raíz.
Las raíces de GC incluyen cosas como:
Entonces, en su caso, una vez que las variables locales a, byc salen del alcance al final de su método, no hay más raíces de GC que contengan, directa o indirectamente, una referencia a cualquiera de sus tres nodos, y serán elegibles para la recolección de basura.
El enlace de TofuBeer tiene más detalles si lo desea.
fuente
Este artículo (ya no está disponible) profundiza sobre el recolector de basura (conceptualmente ... hay varias implementaciones). La parte relevante de su publicación es "A.3.4 inalcanzable":
fuente
La recolección de basura generalmente no significa "limpiar algún objeto si nada más está 'apuntando' a ese objeto" (eso es contar las referencias). Recolección de basura significa aproximadamente encontrar objetos a los que no se puede llegar desde el programa.
Entonces, en su ejemplo, después de que a, byc salgan del alcance, el GC puede recopilarlos, ya que ya no puede acceder a estos objetos.
fuente
Bill respondió tu pregunta directamente. Como dijo Amnon, su definición de recolección de basura es solo un recuento de referencias. Solo quería agregar que incluso los algoritmos muy simples como marcar y barrer y copiar colecciones manejan fácilmente referencias circulares. Por lo tanto, no hay nada mágico al respecto!
fuente