¿Cuáles son las raíces?

¿Cuáles son las raíces en la recolección de basura?

He leído la definición de raíz como “cualquier referencia a la que pueda acceder el progtwig” y la definición de vida es un objeto que se está utilizando, que puede ser una variable estática, variable local.

Estoy un poco confundido con discriminar la diferencia entre los objetos enraizados y en vivo.

¿Cuál es el camino a la raíz? ¿Cómo funcionan los objetos raíz y en vivo?

¿Puede alguien elaborar?

Si piensas en los objetos en la memoria como un árbol, las “raíces” serían los nodos raíz: todos los objetos a los que tu progtwig puede acceder de forma inmediata.

Person p = new Person(); p.car = new Car(RED); p.car.engine = new Engine(); p.car.horn = new AnnoyingHorn(); 

Hay cuatro objetos; una persona, un auto rojo, su motor y su bocina. Dibuja el gráfico de referencia:

  Person [p] | Car (red) / \ Engine AnnoyingHorn 

Y terminará con Person en la “raíz” del árbol. Es en vivo porque se hace referencia a una variable local, p , que el progtwig puede usar en cualquier momento para referirse al objeto Person . Esto también se p.car a los otros objetos, a través de p.car , p.car.engine , etc.

Como Person y todos los demás objetos recursivamente conectados están en vivo, habría problemas si el GC los recogiera.

Considere, sin embargo, si lo siguiente se ejecuta después de un tiempo:

 p.car = new Car(BLUE); 

Y vuelva a dibujar el gráfico:

  Person [p] | Car (blue) Car (red) / \ Engine AnnoyingHorn 

Ahora se puede acceder a la Person través de p y el automóvil azul a través de p.car , pero no hay forma de que se vuelva a acceder al auto rojo o sus partes, ya que no están conectados a una raíz activa. Ellos pueden ser recogidos de forma segura.

Entonces, realmente se trata de tomar cada punto de partida (cada variable local, globales, estáticos, todo en otros hilos y estructuras de stack) – cada raíz – y seguir recursivamente todas las referencias para hacer una lista de todos los objetos “activos”: objetos que están en uso y no son adecuados para su eliminación. Todo lo demás es basura, esperando ser recolectado.

Las raíces GC (Garbage Collector) son objetos especiales para el recolector de basura. El recolector de basura recoge aquellos objetos que no son raíces de GC y no son accesibles por referencias de raíces de GC.

Hay varios tipos de raíces de GC. Un objeto puede pertenecer a más de un tipo de raíz. Los tipos de raíz son:

  • Clase – clase cargada por el cargador de clases del sistema. Tales clases nunca se pueden descargar. Pueden contener objetos a través de campos estáticos. Tenga en cuenta que las clases cargadas por cargadores de clases personalizados no son raíces, a menos que las instancias correspondientes de java.lang.Class sean raíces de otro tipo (s).
  • Hilo – hilo en vivo
  • Stack Local: variable local o parámetro del método Java
  • JNI Local – variable local o parámetro del método JNI
  • JNI Global: referencia global de JNI
  • Monitor utilizado: objetos utilizados como monitor para la sincronización
  • Realizado por JVM: objetos retenidos de la recolección de basura por JVM para sus propósitos. En realidad, la lista de tales objetos depende de la implementación de JVM. Los posibles casos conocidos son: el cargador de clases del sistema, algunas clases de excepciones importantes que la JVM conoce, algunos objetos preasignados para el manejo de excepciones y cargadores de clases personalizados cuando están en el proceso de cargar clases. Desafortunadamente, JVM no proporciona absolutamente ningún detalle adicional para tales objetos. Por lo tanto, le corresponde al analista decidir a qué caso pertenece un determinado “Held by JVM”.

(crédito al sitio web de YourKit )

YourKit no menciona el hecho de que los objetos que esperan su finalización se mantendrán como raíces hasta que el GC ejecute el método finalize() . Eso puede causar la retención transitoria de gráficos grandes de forma inesperada. La regla general es no usar finalizadores (pero esa es una pregunta diferente).

Raíces o raíces de recolección de basura son los objetos que siempre son alcanzables . Si un objeto es siempre alcanzable, entonces no es elegible para la recolección de basura; por lo tanto, las raíces siempre son inelegibles para la recolección. Es el conjunto inicial de objetos desde donde se determina la accesibilidad de todos los demás objetos en el montón.

Otros objetos en el montón accesibles desde las raíces de la recolección de basura se consideran objetos vivos y no son elegibles para la recolección; los objetos que son inalcanzables pueden marcarse para recuperación.

Conozco Java más que la plataforma .Net, así que hablaré solo por uno. En la plataforma Java, las raíces de la GC dependen de la implementación. Sin embargo, en la mayoría del tiempo de ejecución, las raíces de la GC tienden a ser los operandos en la stack (porque actualmente están siendo utilizados por subprocesos) y los miembros de clase (estáticos) de las clases. La accesibilidad se calcula a partir de estos objetos en la mayoría de las JVM. Hay otros casos en los que los parámetros locales y los operandos utilizados por las llamadas JNI se considerarán parte del conjunto raíz, y también se utilizarán para calcular la accesibilidad.

Espero que esto borre cualquier duda persistente sobre qué es una raíz (conjunto) y qué es un objeto vivo.

El sitio web de IBM enumera lo siguiente como raíces de GC.

Tenga en cuenta que algunas de estas son construcciones artificiales realizadas por un analizador de memoria, pero es importante tener en cuenta si está mirando un volcado de stack.

  • Clase del sistema

    Una clase que fue cargada por el cargador de arranque o el cargador de clases del sistema. Por ejemplo, esta categoría incluye todas las clases del archivo rt.jar (parte del entorno de tiempo de ejecución de Java), como las del paquete java.util. *.

  • JNI local

    Una variable local en código nativo, por ejemplo, código JNI definido por el usuario o código interno JVM.

  • JNI global

    Una variable global en código nativo, por ejemplo código JNI definido por el usuario o código interno JVM.

  • Bloque de hilo

    Un objeto al que se hizo referencia desde un bloque de hilos activo.

  • Hilo

    Un hilo en funcionamiento.

  • Monitor ocupado

    Todo lo que llamó a los métodos wait () o notify (), o que está sincronizado, por ejemplo llamando al método synchronized (Object) o ingresando un método synchronized. Si el método era estático, la raíz es una clase; de ​​lo contrario, es un objeto.

  • Java local

    Una variable local. Por ejemplo, parámetros de entrada u objetos de métodos creados localmente que todavía están en la stack de un hilo. Pila nativa

    Parámetros de entrada o salida en código nativo, por ejemplo código JNI definido por el usuario o código interno JVM. Muchos métodos tienen partes nativas, y los objetos que se manejan como parámetros del método se convierten en raíces de recolección de basura. Por ejemplo, parámetros usados ​​para operaciones de archivo, red, E / S o reflexión.

  • Finalizador

    Un objeto que está en cola, esperando que se ejecute un finalizador.

  • Sin finalizar

    Un objeto que tiene un método de finalización, pero que no se finalizó, y aún no se encuentra en la cola del finalizador.

  • Inalcanzable

    Un objeto que es inalcanzable desde cualquier otra raíz, pero que Memory Analyzer marcó como raíz para que el objeto se pueda incluir en un análisis.

    Los objetos inalcanzables a menudo son el resultado de optimizaciones en el algoritmo de recolección de basura. Por ejemplo, un objeto podría ser un candidato para la recolección de basura, pero sería tan pequeño que el proceso de recolección de basura sería demasiado costoso. En este caso, el objeto puede no ser basura recolectada, y puede permanecer como un objeto inalcanzable.

    De forma predeterminada, los objetos inalcanzables se excluyen cuando Memory Analyzer analiza el volcado del montón. Por lo tanto, estos objetos no se muestran en el histogtwig, el árbol del dominador o los resultados de la consulta. Puede cambiar este comportamiento haciendo clic en Archivo> Preferencias …> Herramientas de diagnóstico de IBM para Java – Analizador de memoria, luego seleccionando la checkbox Mantener objetos inalcanzables.

  • Marco de stack de Java

    Un marco de stack Java, que contiene variables locales. Este tipo de raíz de recolección de basura solo se genera si configura las Preferencias para tratar los marcos de stack de Java como objetos. Para obtener más información, consulte Conceptos básicos de Java: subprocesos y consultas de la stack de subprocesos.

  • Desconocido

    Un objeto de tipo raíz desconocido. Algunos volcados, como los archivos de IBM Portable Heap Dump (.phd), no tienen información de raíz. En este caso, el analizador de Memory Analyzer marca los objetos que no tienen referencias entrantes, o que son inalcanzables desde cualquier otra raíz, como desconocidos. Esta acción garantiza que Memory Analyzer retenga todos los objetos en el volcado.

En Java, yo diría que los hilos son los objetos raíz. Cada objeto en vivo puede remontarse a un hilo en vivo. Por ejemplo, un objeto estático es referenciado por una clase, a la que hace referencia un cargador de clase, a la que hace referencia otra clase, a la que hace referencia una instancia de esa clase, … a la que hace referencia un Runnable, al que se hace referencia por un hilo en vivo. ( Nota, las clases pueden ser GC, no pueden ser raíces )

También podemos considerar una raíz “real” para todos los hilos, sin embargo eso está fuera del ámbito de Java estándar. No podemos decir de qué se trata y cómo hace referencia a todos los hilos.