Algo sobre el juicio JVM-objeto

Recientemente, leí el libro "Comprensión profunda de la JVM", y siento que todavía hay algunas diferencias entre los materiales y los libros. Todavía hay algunas cosas en los libros. Así que date prisa y comparte con tus amigos ~

Cómo saber si un objeto puede ser reciclado

Dado que la recolección de basura es que, en primer lugar va a determinar lo que sin duda puede ser reciclado, a menudo decimos que aquí no es un 引用计数法bien 可达性分析法.

Recuento de referencias

Recuento de referencias-> Si un objeto es referenciado una vez por otro lugar, el valor del contador será +1. Por el contrario, cuando el lugar al que se hace referencia no es válido, el valor del contador disminuirá en -1. Cuando el valor del contador es 0, significa que el objeto no tiene referencia a él. Al mismo tiempo, creo que todos también conocen sus inconvenientes, es decir, no puede resolver perfectamente el problema de la dependencia circular.

Manifestación:

package com.montos.test.first;

public class TestReferenceCounting {
   public Object instance = null;
   private byte[] bigSize= new byte[2*1024*1024];
   public static void main(String[] args) {
       TestReferenceCounting objA = new TestReferenceCounting();
       TestReferenceCounting objB = new TestReferenceCounting();
       objA.instance = objB;
       objB.instance = objA;
       objA = null;
       objB =null;
       // objA 与 objB 是否会被回收️?
       System.gc();
   }
}
复制代码

Veamos más arriba cuando el programa se está ejecutando, ¿ se reciclarán los objetos objAy los objetos objB? gc.log

0.148: [GC (System.gc()) 0.149: [SoftReference, 0 refs, 0.0000372 secs]0.149: [WeakReference, 12 refs, 0.0000104 secs]0.149: [FinalReference, 74 refs, 0.0000356 secs]0.149: [PhantomReference, 0 refs, 0 refs, 0.0000104 secs]0.149: [JNI Weak Reference, 0.0000129 secs][PSYoungGen: 6717K->560K(76288K)] 6717K->568K(251392K), 0.0022097 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
0.150: [Full GC (System.gc()) 0.151: [SoftReference, 0 refs, 0.0001038 secs]0.152: [WeakReference, 4 refs, 0.0000127 secs]0.152: [FinalReference, 0 refs, 0.0000085 secs]0.152: [PhantomReference, 0 refs, 0 refs, 0.0000086 secs]0.152: [JNI Weak Reference, 0.0000103 secs][PSYoungGen: 560K->0K(76288K)] [ParOldGen: 8K->371K(175104K)] 568K->371K(251392K), [Metaspace: 2964K->2964K(1056768K)], 0.0065876 secs] [Times: user=0.03 sys=0.00, real=0.00 secs] 
0.157: Total time for which application threads were stopped: 0.0092869 seconds, Stopping threads took: 0.0000445 seconds
Heap
PSYoungGen      total 76288K, used 1966K [0x000000076ab00000, 0x0000000770000000, 0x00000007c0000000)
 eden space 65536K, 3% used [0x000000076ab00000,0x000000076aceb9e0,0x000000076eb00000)
 from space 10752K, 0% used [0x000000076eb00000,0x000000076eb00000,0x000000076f580000)
 to   space 10752K, 0% used [0x000000076f580000,0x000000076f580000,0x0000000770000000)
ParOldGen       total 175104K, used 371K [0x00000006c0000000, 0x00000006cab00000, 0x000000076ab00000)
 object space 175104K, 0% used [0x00000006c0000000,0x00000006c005ce08,0x00000006cab00000)
Metaspace       used 2983K, capacity 4496K, committed 4864K, reserved 1056768K
 class space    used 327K, capacity 388K, committed 512K, reserved 1048576K
复制代码

Como puede ver en el registro anterior, este procedimiento se ejecutó dos veces gc, y ambos System.gc()fueron activados por él. Por primera vez gc, se desencadenó la situación de reciclaje de la generación joven. Se 6717K->568Kpuede ver que jvmno hay reciclaje porque los dos se refieren entre sí (cada objeto aquí contiene una matriz de bytes de 2M). También muestra que la máquina virtual actual no hace referencia al contador para determinar si el objeto está vivo.

Algunos amigos pueden haber notado que también generamos dos objetos aquí objAtambién objB. Entonces la recuperación de la memoria del montón debería 4Mcomenzar a la derecha y a la izquierda de la recuperación de la memoria, ¿por qué comenzó el reciclaje en la 6Mmemoria? ===> Aquí estoy ejecutando una mainfunción (método estático), no la que se ejecuta dentro del contenedor Bean. Entonces, cuando se ejecuta, se genera un objeto de instancia de la clase principal en el montón.

Algoritmo de análisis de accesibilidad

Algoritmo de análisis de accesibilidad-> a través de una serie de objetos llamados "Raíces GC" como punto de partida, comenzando desde estos nodos para buscar hacia abajo, la ruta recorrida por la búsqueda se denomina cadena de referencia, cuando un objeto va a "Raíces GC" "Si no hay una cadena de referencia conectada, prueba que este objeto no está disponible y luego puede reciclarse. Como se muestra a continuación:

La imagen de arriba contiene rootnodos, lo que significa que los objetos subyacentes aún están vivos, mientras que los objetos sobre el subárbol de la derecha se consideran reciclables.

Los objetos que se pueden usar como GC Roots en la pila de máquinas virtuales incluyen:

  • Objetos referenciados en la pila de la máquina virtual (tabla de variables locales en el marco de la pila)
  • Método para ir al objeto al que hace referencia la propiedad estática de la clase
  • Método para ir al objeto al que hace referencia la constante
  • Objetos referenciados por JNI (métodos nativos en general) en la pila de métodos locales

Cotizaciones

Si es a través de los dos algoritmos de recuperación anteriores, si el objeto sobrevive está relacionado con la "referencia". JDK1.2Antes, javala referencia en se definía como: si referenceel valor almacenado en el tipo de datos representa la dirección inicial de otra memoria, se dice que esta memoria representa una referencia. Entonces, según esta definición, el objeto tiene solo dos estados de ser citado y no citado. JDK1.2Posteriormente se expandió: Referencia fuerte, Referencia suave, Referencia débil y Referencia fantasma.

  • Referencias fuertes: referencias como "Object obj = new Object ()", mientras la referencia fuerte todavía exista, el recolector de basura nunca reclamará el objeto referenciado.
  • Referencia suave: Describa algunos objetos útiles pero innecesarios. Para los objetos relacionados con referencias suaves, estos objetos se enumerarán en el rango de recuperación para la recuperación secundaria antes de que ocurra una excepción de desbordamiento de memoria en el sistema. Si no hay suficiente memoria para esta recuperación, se generará una excepción de desbordamiento de memoria. ( JDK1.2Más tarde, SoftReferencese proporcionan clases para implementar referencias suaves).
  • Referencias débiles: Describa objetos no esenciales, pero la fuerza es más débil que las referencias suaves. Los objetos asociados con referencias débiles solo pueden sobrevivir hasta que ocurra la próxima recolección de basura. Cuando el recolector de basura funciona, independientemente de si la memoria actual es suficiente, solo recolectará los objetos a los que se hace referencia débilmente. ( JDK1.2Más tarde, WeakReferencese proporcionan clases para implementar referencias débiles).
  • Referencia virtual: es la relación de referencia más débil. Si un objeto tiene una referencia virtual no afecta su tiempo de supervivencia en absoluto, ni puede obtener una instancia de objeto a través de una referencia virtual. El único propósito de establecer una asociación de referencia virtual para un objeto es ser reciclado por el recolector de basura en este objeto Recibió una notificación del sistema. ( JDK1.2Más tarde, PhantomReferencese proporcionan clases para implementar referencias virtuales).

Supervivencia o muerte del sujeto.

Los objetos que no son accesibles en el algoritmo de análisis de accesibilidad introducido anteriormente no son necesariamente "necesarios para morir". Están temporalmente en una etapa de "prueba". Para declarar verdaderamente la muerte de un objeto, se requieren al menos dos procesos de marcado:

  1. Después de que el análisis de accesibilidad del objeto encuentre que no hay una GC Rootscadena de referencia conectada a él, se marcará por primera vez y se realizará una detección con la condición de que el finalize()método sea ​​necesario para este objeto . Cuando el objeto no anula este método, o la máquina virtual ha llamado a este método, la máquina virtual trata ambos casos como "no es necesario ejecutarlos".
  2. Si se determina que el objeto es necesario para ejecutar el finalize()método, el objeto se colocará en una F-Queuecola llamada . Más tarde, la máquina virtual crea automáticamente un Finalizersubproceso de baja prioridad para ejecutar (solo activará este método y no esperará al final de la ejecución, para evitar la ejecución lenta o bucles interminables que provocan el bloqueo de todo el sistema de reciclaje). Para evitar el reciclaje, siempre y cuando el objeto se vuelva a asociar con cualquier objeto en la cadena de referencia durante la segunda marca.

Manifestación:

public class FinalizesxEscapeGC {
    public static FinalizesxEscapeGC save = null;

    public void isAlive() {
        System.out.println("i am alive");
    }


    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize executed");
        save = this; // 为什么需要用到类的静态变量?
    }

    public static void main(String[] args) throws InterruptedException {
        save = new FinalizesxEscapeGC();

        // 对象第一次拯救自己
        save = null;
        System.gc();
        Thread.sleep(500);

        if (save != null) {
            save.isAlive();
        } else {
            System.out.println("i am dead");
        }

        // 第二次拯救失败
        save = null;
        System.gc();
        Thread.sleep(500);

        if (save != null) {
            save.isAlive();
        } else {
            System.out.println("i am dead");
        }
    }
}
复制代码

Resultados de salida:

finalize executed
i am alive
i am dead
复制代码

Como Demose puede ver en lo anterior , el objeto saveescapó de la primera recolección de basura y se recuperó la segunda vez. Porque el finalize()método de cualquier objeto solo será llamado automáticamente por el sistema una vez, y no será llamado por segunda vez.

Área de método de reciclaje.

Mucha gente piensa que no hay recolección de basura en el área del método (generación permanente). La Javaespecificación de la máquina virtual dice que no se puede requerir que la máquina virtual implemente la recolección de basura en esta área, y la recolección de basura en esta área 性价比no es muy alta. Hay dos partes principales de la recolección de basura en esta área: 废弃常量y 无用的类.

  • Constantes obsoletas
    Cuando no se hace referencia a una constante en el grupo de constantes en ninguna parte, si la recuperación de memoria ocurre en este momento, y si es necesario, el sistema borrará la constante del grupo de constantes.

  • Clase inútil

    • Todas las instancias de esta clase han sido recicladas.
    • El ClassLoader que cargó esta clase ha sido reciclado.
    • El objeto java.lang.Class correspondiente a esta clase no está referenciado en ninguna parte.

    Solo las clases inútiles que cumplen con las tres condiciones anteriores pueden reciclarse. Lo que se dice aquí es "lata", no es lo mismo que el objeto, se reciclará si no se usa.

Este artículo solo presenta brevemente el problema de juzgar si un objeto está vivo o muerto en la JVM. También presenta dos tipos de algoritmos de reciclaje y el problema de juzgar si un objeto está vivo. El siguiente artículo se describirá en detalle junto con el algoritmo de recolección de basura.

Extracto de: "Comprensión profunda de la máquina virtual Java"

Supongo que te gusta

Origin juejin.im/post/5e81ed3df265da480a1a9ecf
Recomendado
Clasificación