13.Conceptos relacionados con la recolección de basura JVM

 Índice de contenidos de los artículos de la serie.

1. Arquitectura JVM y Java

2. Subsistema de carga de clase JVM

3. Descripción general y subprocesos del área de datos de tiempo de ejecución de JVM

4. Contador de programa JVM (registro de PC)

5. Pila de máquinas virtuales JVM

6. Interfaz del método nativo JVM

7. Pila de métodos nativos de JVM

8. montón JVM

9. Área del método JVM

10.JVM-StringTable/StringPool

11.Descripción general de la recolección de basura de JVM

12.Algoritmos relacionados con la recolección de basura JVM

13.Conceptos relacionados con la recolección de basura JVM

14.JVM-recolector de basura


1. Entendiendo System.gc()

De forma predeterminada, Full GC se activará explícitamente llamando a System.gc() o Runtime.getRuntime().gc() , mientras se recicla la generación anterior y la nueva y se intenta liberar la memoria ocupada por los objetos descartados.

Sin embargo, las llamadas a System.gc() vienen con un descargo de responsabilidad de que las llamadas al recolector de basura no están garantizadas. (System.gc() le recuerda a la JVM que quiere realizar una recolección de basura. En cuanto a si se llama, es difícil decirlo)

Los implementadores de JVM pueden determinar el comportamiento del GC de la JVM mediante llamadas a System.gc(). En circunstancias normales, la recolección de basura debe realizarse automáticamente y no es necesario activarla manualmente; de ​​lo contrario, será demasiado problemático . En algunos casos especiales, como si estamos escribiendo un punto de referencia de rendimiento, podemos llamar a System.gc() entre ejecuciones.

ejemplo:

package _03;
​
public class _77_SystemGCTest {
    public static void main(String[] args) {
        new _77_SystemGCTest();
        //提醒jvm的垃圾回收器执行gc,但是不确定是否马上执行gc。 与Runtime.getRuntime().gc();的作用一样。
        System.gc();
​
//        System.runFinalization();//强制调用使用引用的对象的finalize()方法
    }
​
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("SystemGCTest 重写了finalize()");
    }
}
​

Ejecute varias veces, a veces se activa el GC, a veces no. Después de llamar a System.gc();, es posible que no se ejecute a tiempo y que el programa salga antes de que haya GC.

Abra el comentario: System.runFinalization(); se ejecuta varias veces y el resultado es que se activa el GC.

2. Desbordamiento de memoria y pérdida de memoria

2.1 Sin memoria (OOM)

Aunque el desbordamiento de memoria es más fácil de entender que la pérdida de memoria, también es uno de los principales culpables de fallos del programa.

Dado que GC se ha estado desarrollando, en circunstancias normales, a menos que la memoria ocupada por la aplicación crezca muy rápido, lo que hace que la recolección de basura no pueda seguir el ritmo del consumo de memoria, no es probable que ocurra OOM.

En la mayoría de los casos, el GC realizará una recolección de basura de varias edades, si realmente no funciona, se puede ampliar y realizar una operación exclusiva de GC completo, en este momento se recuperará una gran cantidad de memoria para la aplicación. para seguir usándolo.

La explicación de OutOfMemoryError en javadoc es que no hay memoria libre y el recolector de basura no puede proporcionar más memoria. (Por ejemplo, si no hay espacio para guardar las cosas en casa y aún no puedes guardarlas después de ordenarlas, no podrás guardarlas más y se convertirá en OOM).

Primero, hablemos de la situación en la que no hay memoria libre: significa que la memoria dinámica de la máquina virtual Java no es suficiente. Hay dos razones:

(1) La configuración de la memoria dinámica de la máquina virtual Java no es suficiente.

Por ejemplo: puede haber un problema de pérdida de memoria, también es muy probable que el tamaño del montón no sea razonable, por ejemplo, tenemos que procesar una cantidad considerable de datos, pero el tamaño del montón de JVM no se especifica explícitamente o el valor especificado es demasiado pequeña. Podemos ajustarlo a través de los parámetros -Xms y -Xmx.

(2) Se crea una gran cantidad de objetos grandes en el código y el recolector de basura no puede recolectarlos durante mucho tiempo (hay referencias)

Para versiones anteriores de Oracle JDK, debido a que el tamaño de la generación permanente es limitado y la JVM es muy inactiva en cuanto a la recolección de basura de generación permanente (como el reciclaje constante del grupo y la descarga de tipos que ya no son necesarios), cuando continuamos agregando nuevos tipos , OutOfMemoryError también es muy común en la generación permanente, especialmente cuando se genera una gran cantidad de tipos dinámicos en tiempo de ejecución; el caché de cadenas interno similar ocupa demasiado espacio, lo que también puede causar problemas OOM. La información de excepción correspondiente se marcará y relacionará con la generación permanente: " java.lang.OutOfMemoryError: PermGen space ".

Con la introducción del área de metadatos, la memoria en el área de método ya no es tan vergonzosa, por lo que el OOM correspondiente ha cambiado. Cuando ocurre OOM, el mensaje de excepción se convierte en: " java.lang.OutofMemoryError: Metaspace ". La memoria directa insuficiente (memoria local) también puede causar OOM.

El significado implícito aquí es que antes de que se genere un OutOfMemoryError, el recolector de basura generalmente se activa y hace todo lo posible para limpiar el espacio.

  • Por ejemplo: en el análisis del mecanismo de referencia, implica que la JVM intente reciclar los objetos señalados por referencias suaves, etc.
  • En el método java.nio.Bits.reserveMemory(), podemos ver claramente que se llamará a System.gc() para limpiar espacio.

Por supuesto, el recolector de basura no se activará en todas las circunstancias.

  • Por ejemplo, si asignamos un objeto muy grande, similar a una matriz muy grande que excede el tamaño máximo del montón, la JVM puede determinar que la recolección de basura no puede resolver este problema, por lo que arroja directamente un OutOfMemoryError.

2.2 Pérdida de memoria

(Las pérdidas de memoria pueden provocar un desbordamiento de memoria (OOM), pero no necesariamente OOM)

También conocida como "fuga de almacenamiento". Estrictamente hablando, se denomina pérdida de memoria solo cuando el programa ya no utilizará los objetos, pero el GC no puede reciclarlos. (Es un poco como comprar una casa y hay puestos (escaleras y paredes) que no puedes usar, pero el dinero aún cuenta al comprar una casa).

Pero en realidad, muchas veces algunas malas prácticas (o negligencias) harán que el ciclo de vida del objeto sea muy largo o incluso provocarán OOM, lo que también se puede denominar " pérdida de memoria" en un sentido amplio .

Aunque una pérdida de memoria no provocará que el programa falle inmediatamente, una vez que se produzca una pérdida de memoria, la memoria disponible en el programa se erosionará gradualmente hasta que se agote toda la memoria y, finalmente, se producirá una excepción OutOfMemory, lo que provocará que el programa falle.

Tenga en cuenta que el espacio de almacenamiento aquí no se refiere a la memoria física, sino al tamaño de la memoria virtual, que depende del tamaño del área de intercambio del disco.

Ejemplo:

1. Modo singleton

El ciclo de vida de un singleton es tan largo como la aplicación, por lo que en un programa singleton, si contiene una referencia a un objeto externo , el objeto externo no se puede reciclar, lo que provocará pérdidas de memoria.

2. Algunos recursos que proporcionan cierre no se cierran, lo que provoca pérdidas de memoria.

Las conexiones de base de datos (dataSourse.getConnection()), las conexiones de red (socket) y las conexiones io deben cerrarse manualmente; de ​​lo contrario, no se pueden reciclar.

3. Detener el mundo

Stop-the-World, o STW para abreviar, se refiere a la pausa de la aplicación que ocurre cuando ocurre un evento de GC. Cuando ocurre una pausa, todo el hilo de la aplicación se suspenderá sin ninguna respuesta , un poco como una sensación de estancamiento, esta pausa se llama STW.

  • La enumeración de nodos raíz (GC Roots) en el algoritmo de análisis de accesibilidad hará que todos los subprocesos de ejecución de Java se detengan. (GC Roots seguirá cambiando, por lo que se requiere STW)

    • El análisis debe realizarse en una instantánea consistente.
    • La coherencia significa que todo el sistema de ejecución parece estar congelado en un momento determinado durante todo el análisis.
    • Si la relación de referencia del objeto continúa cambiando durante el proceso de análisis, no se puede garantizar la precisión de los resultados del análisis.

Los subprocesos de la aplicación interrumpidos por STW se reanudarán después de completar el GC. Las interrupciones frecuentes harán que los usuarios se sientan como casetes de películas debido a la baja velocidad de la red, por lo que debemos reducir la aparición de STW.

El evento STW no tiene nada que ver con el GC que se utiliza, todos los GC tienen este evento.

Incluso G1 no puede evitar por completo la situación de Stop-the-World: solo se puede decir que el recolector de basura es cada vez mejor, la eficiencia del reciclaje es cada vez mayor y el tiempo de pausa se acorta tanto como sea posible.

La JVM inicia y completa automáticamente STW en segundo plano . Cuando el usuario sea invisible, detenga todos los subprocesos de trabajo normales del usuario.

No utilice System.gc() durante el desarrollo; provocará Stop-the-World.

ejemplo:

package _03;
​
import java.util.ArrayList;
import java.util.List;
​
public class _79_StopTheWorldDemo {
    public static class WorkThread extends Thread {
        List<byte[]> list = new ArrayList<byte[]>();
​
        public void run() {
            try {
                while (true) {
                    for(int i = 0;i < 1000;i++){
                        byte[] buffer = new byte[1024];
                        list.add(buffer);
                    }
​
                    if(list.size() > 10000){
                        list.clear();
                        //会触发full gc,进而会出现STW事件。 出现STW就会卡顿,打印的时间就不是每隔一秒打印一次了
                        System.gc();
                    }
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }
​
    public static class PrintThread extends Thread {
        public final long startTime = System.currentTimeMillis();
​
        public void run() {
            try {
                while (true) {
                    // 每秒打印时间信息
                    long t = System.currentTimeMillis() - startTime;
                    System.out.println(t / 1000 + "." + t % 1000);
                    Thread.sleep(1000);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }
​
    public static void main(String[] args) {
        WorkThread w = new WorkThread();
        PrintThread p = new PrintThread();
//        w.start();
        p.start();
    }
}

Cuando se ejecuta, puede ver que no hay ningún proceso STW y que el intervalo entre tiempos de impresión adyacentes es básicamente de 1 segundo.

0,0
1,0
2,0
3,1
4,2
5,3
6,4
7,4
8,4
...

Comentarios abiertos

Como resultado de la operación, STW se congelará cuando aparezca y el tiempo de impresión ya no se imprimirá cada segundo, lo que prueba indirectamente la existencia de STW.

0,0
1,2
2,6
3,6
4,8
5,11
6,14
7,17
...

4. Paralelismo y concurrencia de recolección de basura.

4.1 Concurrente

En el sistema operativo, significa que hay varios programas en un período de tiempo desde que se inician hasta que se ejecutan, y todos estos programas se ejecutan en el mismo procesador.

La concurrencia no es "simultánea" en el verdadero sentido. Es solo que la CPU divide un período de tiempo en varios segmentos de tiempo (intervalos de tiempo) y luego alterna entre estos intervalos de tiempo. Dado que la velocidad de procesamiento de la CPU es muy rápida, siempre que el tiempo Los intervalos manejados adecuadamente pueden hacer que los usuarios sientan que se están ejecutando varias aplicaciones al mismo tiempo. (Los ejemplos de comer y hablar por teléfono mencionados anteriormente)

4.2 Paralelo

Cuando el sistema tiene más de una CPU, cuando una CPU ejecuta un proceso, la otra CPU puede ejecutar otro proceso. Los dos procesos no toman los recursos de la CPU del otro y pueden continuar al mismo tiempo. A esto lo llamamos paralelo (Paralelo).

De hecho, el factor que determina el paralelismo no es la cantidad de CPU, sino la cantidad de núcleos de CPU. Por ejemplo, se pueden paralelizar varios núcleos de una CPU.

Adecuado para escenarios de interacción débil, como informática científica y procesamiento en segundo plano.

4.3 Concurrencia vs Paralelismo

Compara los dos:

La concurrencia se refiere a que varias cosas suceden al mismo tiempo dentro del mismo período de tiempo .

Paralelo se refiere a que varias cosas suceden al mismo tiempo al mismo tiempo .

Múltiples tareas simultáneas compiten por recursos entre sí.

Múltiples tareas paralelas no compiten entre sí por los recursos.

El paralelismo solo ocurrirá en el caso de múltiples CPU o múltiples núcleos en una CPU. De lo contrario, las cosas que parecen suceder al mismo tiempo en realidad se ejecutan al mismo tiempo.

4.4 Paralelismo y concurrencia de recolección de basura.

La concurrencia y el paralelismo, en el contexto de hablar de recolectores de basura, se pueden explicar de la siguiente manera:

  • Paralelo (Paralle1): se refiere a varios subprocesos de recolección de basura que funcionan en paralelo, pero en este momento el subproceso del usuario todavía está en estado de espera.

    • Como ParNew, Parallel Scavenge, Parallel Old;
  • De serie

    • En comparación con el concepto de paralelismo, ejecución de un solo subproceso.
    • Si no hay suficiente memoria, el programa se pausa y se inicia el recolector de basura JVM para la recolección de basura. Después del reciclaje, inicie nuevamente el hilo del programa.

La concurrencia y el paralelismo, en el contexto de hablar de recolectores de basura, se pueden explicar de la siguiente manera:

Concurrencia (concurrente): se refiere al hilo del usuario y al hilo de recolección de basura que se ejecutan al mismo tiempo (pero no necesariamente en paralelo, pueden ejecutarse alternativamente). El hilo de recolección de basura no detendrá la ejecución del programa de usuario durante la ejecución.

  • El programa de usuario continúa ejecutándose, mientras que el subproceso del recolector de basura se ejecuta en otra CPU;

    Tales como: CMS, G1

5. Lugares seguros y zonas seguras

(Los hilos de usuario solo pueden detenerse en puntos o áreas seguras).

5.1 Punto seguro

Cuando se ejecuta el programa, no es posible pausar e iniciar GC en todos los lugares. Solo puede pausar e iniciar GC en ubicaciones específicas. Estas ubicaciones se denominan "Puntos seguros".

La elección del punto seguro es muy importante. Si son muy pocos, el GC puede esperar demasiado, y si son demasiado frecuentes, pueden causar problemas de rendimiento en tiempo de ejecución. El tiempo de ejecución de la mayoría de las instrucciones es muy corto y el estándar suele basarse en " si tiene características que permitan que el programa se ejecute durante un tiempo prolongado ". Por ejemplo: seleccione algunas instrucciones con tiempos de ejecución prolongados como puntos seguros, como llamadas a métodos, saltos de bucle y saltos de excepción .

¿Cómo comprobar que todos los subprocesos se ejecutan hasta el punto seguro más cercano y se detienen cuando se produce GC?

  • Interrupción preventiva : ( actualmente ninguna máquina virtual la adopta ) interrumpe todos los subprocesos primero. Si hay subprocesos que no están en el punto seguro, restaure el subproceso y déjelo correr hasta el punto seguro.
  • Interrupción activa : establezca un indicador de interrupción, y cada subproceso sondea activamente este indicador cuando se ejecuta hasta el punto seguro. Si el indicador de interrupción es verdadero, se interrumpirá y suspenderá.

5.2 Región segura

El mecanismo Safepoint garantiza que cuando se ejecute el programa, encontrará un punto seguro que pueda ingresar al GC en un corto período de tiempo. Pero ¿qué pasa cuando el programa "no se ejecuta"? Por ejemplo, cuando un subproceso está en estado de suspensión o bloqueado, el subproceso no puede responder a la solicitud de interrupción de la JVM y "camina" hasta un punto seguro para interrumpir la suspensión, y es poco probable que la JVM espere a que se despierte el subproceso. . Para esta situación se necesita una región segura (Safe Region) para solucionarla.

La zona segura significa que la relación de referencia del objeto no cambiará en un fragmento de código. Es seguro iniciar GC en cualquier lugar de esta zona. También podemos pensar en Safe Region como un Safepoint ampliado.

Cuando realmente se ejecuta:

  • 1. Cuando un subproceso se ejecuta en el código de Región segura, primero se marca como si hubiera ingresado a la Región segura. Si se produce GC durante este período, la JVM ignorará el subproceso marcado como Región segura.
  • 2. Cuando el hilo esté a punto de salir de la región segura, verificará si la JVM ha completado el GC. Si se completa, continuará ejecutándose. De lo contrario, el hilo debe esperar hasta recibir una señal de que puede hacerlo de manera segura. abandonar la Región Segura;

6. Volvamos a hablar de citas.

Esperamos describir una clase de objetos que se pueden mantener en la memoria cuando hay suficiente espacio de memoria y se pueden descartar si el espacio de memoria aún es limitado después de la recolección de basura.

[Preguntas de la entrevista parciales y de muy alta frecuencia] ¿Cuál es la diferencia entre citas fuertes, citas suaves, citas débiles y citas virtuales? ¿Cuáles son los escenarios de uso específicos?

Después de la versión 1.2 de JDK, Java amplió el concepto de referencias y las dividió en:

  • Referencia fuerte
  • Referencia suave
  • Referencia débil
  • Referencia fantasma

Estas cuatro fortalezas de las citas se debilitan gradualmente en secuencia. A excepción de las referencias fuertes, los otros tres tipos de referencias se pueden encontrar en el paquete java.1ang.ref. La siguiente figura muestra las clases correspondientes a estos tres tipos de referencia y los desarrolladores pueden usarlas directamente en las aplicaciones.

En la subclase Referencia, solo la referencia del finalizador es visible dentro del paquete. Los otros tres tipos de referencia son públicos y se pueden usar directamente en la aplicación.

  • Referencia fuerte : la definición más tradicional de "referencia" se refiere a la asignación de referencia que es omnipresente en el código del programa, es decir, una relación de referencia como "Objeto obj = nuevo Objeto ()". En cualquier caso, mientras exista una relación de referencia sólida, el recolector de basura nunca recuperará el objeto referenciado.
  • SoftReference : antes de que el sistema esté a punto de experimentar un desbordamiento de memoria, estos objetos se incluirán en el alcance del reciclaje para un segundo reciclaje. Si no hay suficiente memoria después de este reciclaje, se generará una excepción de desbordamiento de memoria. (Si no hay suficiente memoria, recíclela; si hay suficiente memoria, consérvela).
  • Referencia débil : los objetos asociados con referencias débiles solo pueden sobrevivir hasta la próxima recolección de basura. Cuando el recolector de basura funciona, los objetos asociados con referencias débiles se reciclarán independientemente de si el espacio de memoria es suficiente. (Si hay suficiente memoria, se reciclará y, si se encuentra, se reciclará inmediatamente)
  • Referencia fantasma : si un objeto tiene una referencia virtual no afectará en absoluto su tiempo de supervivencia y es imposible obtener una instancia de un objeto a través de una referencia virtual. El único propósito de establecer una asociación de referencia virtual para un objeto es recibir una notificación del sistema cuando el recolector reclama el objeto. (Seguimiento de reciclaje de objetos)

6.1 Referencias fuertes

En los programas Java, el tipo de referencia más común es la referencia fuerte ( más del 99% de los sistemas ordinarios son referencias fuertes ), que es nuestra referencia de objeto ordinaria más común y el tipo de referencia predeterminado.

Cuando utiliza el nuevo operador en el lenguaje Java para crear un nuevo objeto y asignarlo a una variable, la variable se convierte en una fuerte referencia al objeto.

Se puede acceder a un objeto fuertemente referenciado y el recolector de basura nunca recuperará el objeto referenciado.

Para un objeto ordinario, si no hay otras relaciones de referencia, siempre que exceda el alcance de la referencia o asigne explícitamente la referencia correspondiente (fuerte) a nu11, se puede recolectar como basura. Por supuesto, el tiempo de reciclaje específico aún Depende de la basura Estrategia de recolección.

Por el contrario, los objetos con referencias suaves, referencias débiles y referencias virtuales son de alcance suave, de alcance débil y de alcance virtual, y pueden reciclarse bajo ciertas condiciones. Por lo tanto, las referencias fuertes son una de las principales causas de las pérdidas de memoria de Java.

ejemplo:

package _03;
​
public class _80_StrongReferenceTest {
    public static void main(String[] args) {
        StringBuffer str = new StringBuffer ("Hello WORD");
        StringBuffer str1 = str;
​
        str = null;
        System.gc();
​
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
​
        System.out.println(str1);
    }
}

Corre, puedes ver que no hay reciclaje.

Hola PALABRA

Resumir:

Las dos referencias en este ejemplo son referencias fuertes. Las referencias fuertes tienen las siguientes características:

  • Las referencias fuertes pueden acceder directamente al objeto de destino.
  • El sistema no reciclará el objeto señalado por la referencia fuerte en ningún momento. La máquina virtual preferirá lanzar una excepción OOM que reciclar el objeto señalado por la referencia fuerte.
  • Las referencias fuertes pueden provocar pérdidas de memoria.

6.2 Referencias suaves

(Las referencias suaves y débiles se pueden conservar si hay suficiente espacio y borrarse si no hay suficiente espacio. Por ejemplo, el caché puede usar estas dos).

Las referencias suaves se utilizan para describir algunos objetos que son útiles pero no necesarios. Los objetos que solo están asociados con referencias suaves se enumerarán en el alcance del reciclaje para un segundo reciclaje antes de que ocurra una excepción de desbordamiento de memoria en el sistema. Si no hay suficiente memoria para este reciclaje, se generará un desbordamiento de memoria anormal.

Las referencias suaves se utilizan a menudo para implementar cachés sensibles a la memoria. Por ejemplo: el caché utiliza referencias suaves. Si hay memoria libre, la caché se puede retener temporalmente y borrar cuando la memoria sea insuficiente, lo que garantiza que la caché se utilizará sin quedarse sin memoria. (Las clases internas de MyBatis usan referencias suaves)

Cuando el recolector de basura decide reciclar un objeto accesible por software en un momento determinado, limpiará la referencia suave y, opcionalmente, almacenará la referencia en una cola de referencia (Cola de referencia).

Es similar a una referencia débil, excepto que la máquina virtual Java intenta mantener viva la referencia suave durante más tiempo y la limpia como último recurso.

Después de la versión 1.2 de JDK, se proporciona la clase java.lang.ref.SoftReference para implementar referencias suaves.

// 声明强引用
Object obj = new Object();
// 创建一个软引用
SoftReference<Object> sf = new SoftReference<>(obj);
obj = null; //销毁强引用

(Como se mencionó anteriormente, todos son accesibles: los objetos con referencias suaves, referencias débiles y referencias virtuales son accesibles de manera suave, accesibles débilmente y accesibles virtualmente).

6.3 Citas débiles

Las referencias débiles también se utilizan para describir objetos no esenciales. Los objetos asociados con referencias débiles solo pueden sobrevivir hasta que se produzca la siguiente recolección de basura . Durante la GC del sistema, siempre que se encuentre una referencia débil, los objetos asociados solo con referencias débiles se reciclarán independientemente de si el espacio del montón del sistema es suficiente.

Descubre y recicla

Sin embargo, dado que el hilo del recolector de basura generalmente tiene una prioridad muy baja, es posible que los objetos que contienen referencias débiles no se encuentren rápidamente. En este caso, el objeto de referencia débil puede existir durante un período de tiempo más largo .

Las referencias débiles son lo mismo que las referencias suaves. Al construir una referencia débil, también puede especificar una cola de referencia. Cuando el objeto de referencia débil se recicla, se agregará a la cola de referencia especificada. A través de esta cola, el estado de reciclaje del El objeto puede ser rastreado.

Las referencias suaves y las referencias débiles son muy adecuadas para guardar datos de caché prescindibles. Si hace esto, cuando la memoria del sistema sea insuficiente, estos datos almacenados en caché se reciclarán sin provocar un desbordamiento de la memoria. Cuando los recursos de memoria son suficientes, estos datos almacenados en caché pueden existir durante mucho tiempo, lo que acelera el sistema.

Después de la versión 1.2 de JDK, se proporciona la clase java.lang.ref.WeakReference para implementar referencias débiles.

// 声明强引用
Object obj = new Object();
// 创建一个弱引用
WeakReference<Object> sf = new WeakReference<>(obj);
obj = null; //销毁强引用

La mayor diferencia entre los objetos de referencia débiles y los objetos de referencia suaves es que cuando GC se recicla, necesita usar un algoritmo para verificar si se reciclan los objetos de referencia suaves, mientras que para los objetos de referencia débiles, GC siempre los recicla. Los objetos de referencia débiles son más fáciles y rápidos de reciclar mediante GC .

Pregunta de la entrevista: ¿Alguna vez ha utilizado WeakHashMap en desarrollo?

6.4 Referencias virtuales

Seguimiento del reciclaje de objetos

También conocida como "referencia fantasma" o "referencia fantasma", es la más débil de todos los tipos de referencia.

Si un objeto tiene una referencia virtual no determina en absoluto el ciclo de vida del objeto. Si un objeto solo contiene una referencia virtual, es casi lo mismo que no tener referencia y el recolector de basura puede recolectarlo en cualquier momento.

No se puede utilizar solo ni obtener el objeto referenciado a través de una referencia virtual. Al intentar obtener un objeto a través del método get() de una referencia virtual, siempre es nulo.

El único propósito de establecer una asociación de referencia virtual para un objeto es realizar un seguimiento del proceso de recolección de basura. Por ejemplo: puede recibir una notificación del sistema cuando el recolector recicla este objeto.

Las referencias virtuales deben usarse con colas de referencia. Se debe proporcionar una referencia virtual como parámetro al crear una cola de referencia. Cuando el recolector de basura se está preparando para reciclar un objeto, si descubre que todavía tiene una referencia virtual, agregará la referencia virtual a la cola de referencias después de reciclar el objeto para notificar a la aplicación sobre el estado de reciclaje del objeto.

Dado que las referencias virtuales pueden rastrear el tiempo de reciclaje de los objetos, algunas operaciones de liberación de recursos también se pueden ejecutar y registrar en referencias virtuales.

Después de la versión 1.2 de JDK, se proporciona la clase java.lang.ref.PhantomReference para implementar referencias virtuales. '

// 声明强引用
Object obj = new Object();
// 声明引用队列
ReferenceQueue phantomQueue = new ReferenceQueue();
// 声明虚引用(还需要传入引用队列)
PhantomReference<Object> sf = new PhantomReference<>(obj, phantomQueue);
obj = null; 

6.5 Referencias de terminador

Se utiliza para implementar el método finalize() del objeto y también se puede llamar referencia de finalizador.

No se requiere codificación manual, funciona internamente con colas de referencia.

Durante la GC, las referencias del finalizador se ponen en cola (similar a las referencias virtuales). El subproceso Finalizer encuentra el objeto referenciado a través de la referencia del finalizador y llama a su método finalize () El objeto referenciado no se recicla hasta el segundo GC.

Supongo que te gusta

Origin blog.csdn.net/weixin_47465999/article/details/127104039
Recomendado
Clasificación