Cuatro tipos de referencias en Java, referencias fuertes, referencias débiles, referencias suaves y referencias fantasmas

Después de JDK1.2, las referencias a objetos se dividen en cuatro estados, a saber, referencias fuertes, referencias suaves, referencias débiles y referencias virtuales. De esta forma, puede controlar el ciclo de vida del objeto de forma más flexible.

1. Fuerte referencia (StrongReference)

      Las citas fuertes son las citas más utilizadas. Si un objeto tiene una referencia sólida, el recolector de basura nunca lo reclamará . como sigue:

Object o=new Object();   //  强引用

      Cuando el espacio de memoria es insuficiente, la máquina virtual Java prefiere lanzar un error OutOfMemoryError para hacer que el programa finalice de manera anormal y no resolvería el problema de la memoria insuficiente recuperando objetos con referencias fuertes a voluntad. De lo contrario, utilice los siguientes métodos para debilitar la referencia, de la siguiente manera:

o=null;     // 帮助垃圾收集器回收此对象

      Establecido explícitamente o en nulo, o más allá del alcance del ciclo de vida del objeto, gc piensa que el objeto no tiene una referencia, entonces el objeto se puede reciclar. Cuándo recolectarlo depende del algoritmo de gc.

Por ejemplo:

    public void test(){
        Object o=new Object();
        // 省略其他操作
    }

Hay una fuerte referencia dentro de un método, esta referencia se almacena en la pila y el contenido de referencia real (Objeto) se almacena en el montón. Cuando se complete este método, saldrá de la pila de métodos, la referencia al contenido no existe y el Objeto se reciclará.

Pero si esta o es una variable global, debe asignarse a nulo cuando el objeto no se usa, porque las referencias fuertes no se recolectarán como basura.

Las referencias sólidas tienen usos muy importantes en la práctica, por ejemplo, el código fuente de implementación de ArrayList:

 private transient Object[] elementData;
    public void clear() {
            modCount++;
            // Let gc do its work
            for (int i = 0; i < size; i++)
                elementData[i] = null;
            size = 0;
    }

Una matriz de variable privada elementData se define en la clase ArrayList. Al llamar al método para borrar la matriz, puede ver que al contenido de cada matriz se le asigna un valor de nulo. A diferencia de elementData = null, la referencia fuerte todavía existe para evitar la reasignación de memoria al agregar elementos en llamadas posteriores a add () y otros métodos. El uso de métodos como el método clear () para liberar memoria es particularmente aplicable a los tipos de referencia almacenados en la matriz, de modo que la memoria pueda liberarse a tiempo.


2. Soft Reference (SoftReference)

        Si un objeto tiene solo referencias suaves, el espacio de memoria es suficiente, el recolector de basura no lo reclamará; si el espacio de memoria es insuficiente, se reclamará la memoria de estos objetos . Siempre que el recolector de basura no lo reclame, el programa puede usar el objeto. Las referencias suaves se pueden usar para implementar cachés sensibles a la memoria ( mybatis SoftCache usa referencias débiles, y el mapa en ThreadLocal también usa referencias suaves [para prevenir pérdidas de memoria] ).  

Formato de declaración de referencia blanda:

import java.lang.ref.SoftReference;
 
public class TestRef {
    public static void main(String args[]) {
        SoftReference<String> str = new SoftReference<String>(new String("abc"));
        System.out.println(str.get());
        //通知JVM进行内存回收
        System.gc();
        System.out.println(str.get());
    }
}

    Resultado de salida:

Se puede ver que la JVM tiene suficiente memoria en este momento y los objetos asociados con referencias suaves aún no se han reclamado .

 

 String str=new String("abc");                                     // 强引用
 SoftReference<String> softRef=new SoftReference<String>(str);     // 软引用  

Cuando la memoria es insuficiente, equivale a:

    If(JVM.内存不足()) {
       str = null;  // 转换为软引用
       System.gc(); // 垃圾回收器进行回收
    }

Las referencias suaves tienen aplicaciones importantes en la práctica, como el botón de retroceso de un navegador. Al presionar hacia atrás, ¿el contenido de la página web que se muestra durante el respaldo debe solicitarse nuevamente o recuperarse del caché? Depende de la estrategia de implementación específica.

(1) Si una página web se recicla al final de la navegación, debe reconstruirse cuando presiona Atrás para ver la página navegada anteriormente.

(2) Si almacena las páginas web exploradas en la memoria, provocará una gran pérdida de memoria e incluso provocará un desbordamiento de la memoria.

En este momento, puede utilizar referencias suaves

    Browser prev = new Browser();               // 获取页面进行浏览
    SoftReference sr = new SoftReference(prev); // 浏览完毕后置为软引用        
    if(sr.get()!=null){
        rev = (Browser) sr.get();           // 还没有被回收器回收,直接获取
    }else{
        prev = new Browser();               // 由于内存吃紧,所以对软引用的对象回收了
        sr = new SoftReference(prev);       // 重新构建
    }

Esto resuelve muy bien el problema real.

       Se puede usar una referencia suave junto con una cola de referencia (ReferenceQueue). Si el objeto al que hace referencia la referencia suave es reciclado por el recolector de basura, la máquina virtual Java agregará la referencia suave a la cola de referencia asociada con ella.


3. Referencia débil (referencia débil)

      La diferencia entre referencias débiles y referencias suaves es que solo los objetos con referencias débiles tienen un ciclo de vida más corto. En el proceso del subproceso del recolector de basura que escanea el área de memoria bajo su jurisdicción, una vez que se encuentra un objeto con solo referencias débiles, su memoria se recuperará independientemente de si el espacio de memoria actual es suficiente . Sin embargo, debido a que el recolector de basura es un subproceso de baja prioridad, es posible que los objetos que solo tienen referencias débiles no se encuentren rápidamente.

  String str=new String("abc");    
  WeakReference<String> abcWeakRef = new WeakReference<String>(str);
  str=null;  

Cuando el recolector de basura escanea y recolecta, es equivalente a:

    str = null;
    System.gc();

   Si este objeto se usa ocasionalmente y desea obtenerlo en cualquier momento cuando lo use, pero no desea afectar la recolección de basura de este objeto, entonces debe usar la Referencia débil para recordar este objeto.   

   El siguiente código hará que str nuevamente sea una referencia sólida:

String  abc = abcWeakRef.get();

Una referencia débil se puede usar junto con una cola de referencia (ReferenceQueue). Si el objeto al que hace referencia la referencia débil es recolectado como basura, la máquina virtual Java agregará la referencia débil a la cola de referencia asociada con ella.

Cuando desea hacer referencia a un objeto, pero este objeto tiene su propio ciclo de vida y no desea intervenir en el ciclo de vida de este objeto, utiliza referencias débiles.

Esta referencia no tendrá ninguna influencia adicional en el juicio de recolección de basura del objeto.

    public class ReferenceTest {
     
        private static ReferenceQueue<VeryBig> rq = new ReferenceQueue<VeryBig>();
     
        public static void checkQueue() {
            Reference<? extends VeryBig> ref = null;
            while ((ref = rq.poll()) != null) {
                if (ref != null) {
                    System.out.println("In queue: "    + ((VeryBigWeakReference) (ref)).id);
                }
            }
        }
     
        public static void main(String args[]) {
            int size = 3;
            LinkedList<WeakReference<VeryBig>> weakList = new LinkedList<WeakReference<VeryBig>>();
            for (int i = 0; i < size; i++) {
                weakList.add(new VeryBigWeakReference(new VeryBig("Weak " + i), rq));
                System.out.println("Just created weak: " + weakList.getLast());
     
            }
     
            System.gc();
            try { // 下面休息几分钟,让上面的垃圾回收线程运行完成
                Thread.currentThread().sleep(6000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            checkQueue();
        }
    }
     
    class VeryBig {
        public String id;
        // 占用空间,让线程进行回收
        byte[] b = new byte[2 * 1024];
     
        public VeryBig(String id) {
            this.id = id;
        }
     
        protected void finalize() {
            System.out.println("Finalizing VeryBig " + id);
        }
    }
     
    class VeryBigWeakReference extends WeakReference<VeryBig> {
        public String id;
     
        public VeryBigWeakReference(VeryBig big, ReferenceQueue<VeryBig> rq) {
            super(big, rq);
            this.id = big.id;
        }
     
        protected void finalize() {
            System.out.println("Finalizing VeryBigWeakReference " + id);
        }
    }

El resultado final es:

    Just created weak: com.javabase.reference.VeryBigWeakReference@1641c0
    Just created weak: com.javabase.reference.VeryBigWeakReference@136ab79
    Just created weak: com.javabase.reference.VeryBigWeakReference@33c1aa
    Finalizing VeryBig Weak 2
    Finalizing VeryBig Weak 1
    Finalizing VeryBig Weak 0
    In queue: Weak 1
    In queue: Weak 2
    In queue: Weak 0


4. Referencia fantasma (PhantomReference)

     Como su nombre lo indica, "referencia virtual" no es más que una referencia virtual. A diferencia de otros tipos de referencias, una referencia virtual no determina el ciclo de vida de un objeto. Si un objeto contiene solo referencias fantasmas, entonces es lo mismo que sin ninguna referencia, y el recolector de basura puede recolectarlo en cualquier momento.

    Las referencias fantasmas se utilizan principalmente para rastrear las actividades de los objetos que recicla el recolector de basura. Una diferencia entre la referencia virtual y la referencia suave y la referencia débil es que la referencia virtual debe usarse junto con la cola de referencia (ReferenceQueue). Cuando el recolector de basura está a punto de reclamar un objeto, si encuentra que tiene una referencia fantasma, agregará la referencia fantasma a la cola de referencia asociada con él antes de reclamar la memoria del objeto.

 

5. Resumen

 Los niveles de referencias de Java 4 de mayor a menor son:

             Referencia fuerte> Referencia suave> Referencia débil> Referencia fantasma

Mire la diferencia entre ellos en la recolección de basura a través del diagrama:


Cuando el recolector de basura recolecta, algunos objetos serán recolectados y otros no. El recolector de basura marcará los objetos supervivientes del objeto raíz Object y luego reciclará algunos objetos inalcanzables y algunos objetos referenciados. Si no está familiarizado con esto, puede consultar el siguiente artículo:

Portal: gestión de memoria Java http://blog.csdn.net/mazhimazh/article/category/1907599

Explíquelo a través de la tabla, de la siguiente manera:

Tipo de referencia Hora de recolección de basura utilizar Tiempo de supervivencia
Citación fuerte Nunca Estado general del objeto Terminar cuando la JVM deja de ejecutarse
Referencia suave Cuando la memoria es baja Caché de objetos Terminar cuando la memoria sea insuficiente
Referencia débil Durante la recolección de basura Caché de objetos Terminar después de que gc se ejecute
Referencia fantasma Desconocido Desconocido Desconocido

 

 

 

 

 

 

Articulo de referencia:

https://blog.csdn.net/mazhimazh/article/details/19752475

https://blog.csdn.net/qq_33591903/article/details/82024257

Supongo que te gusta

Origin blog.csdn.net/qianzhitu/article/details/103103667
Recomendado
Clasificación