Quatro tipos de referências em Java, referências fortes, referências fracas, referências suaves e referências fantasmas

Após JDK1.2, as referências de objeto são divididas em quatro estados, a saber, referências fortes, referências suaves, referências fracas e referências virtuais. Desta forma, você pode controlar o ciclo de vida do objeto de forma mais flexível.

1. Referência forte (StrongReference)

      Citações fortes são as citações mais comumente usadas. Se um objeto tiver uma referência forte, o coletor de lixo nunca irá recuperá-lo . do seguinte modo:

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

      Quando o espaço de memória é insuficiente, a máquina virtual Java prefere lançar OutOfMemoryError para fazer o programa encerrar de forma anormal e não resolveria o problema de memória insuficiente recuperando objetos com referências fortes à vontade. Caso contrário, use os seguintes métodos para enfraquecer a referência, como segue:

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

      Definido explicitamente como nulo, ou além do escopo do ciclo de vida do objeto, gc pensa que o objeto não tem uma referência, então o objeto pode ser reciclado. Quando coletar depende do algoritmo de gc.

Por exemplo:

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

Há uma referência forte dentro de um método, essa referência é armazenada na pilha e o conteúdo de referência real (Objeto) é armazenado no heap. Quando este método for concluído, ele sairá da pilha de métodos, a referência ao conteúdo não existe e o Objeto será reciclado.

Mas se este o for uma variável global, ele precisa ser atribuído a null quando o objeto não for usado, porque referências fortes não serão coletadas como lixo.

As referências fortes têm usos muito importantes na prática, por exemplo, o código-fonte de implementação 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;
    }

Um array elementData de variável privada é definido na classe ArrayList. Ao chamar o método para limpar o array, você pode ver que o conteúdo de cada array recebe um valor null. Diferente de elementData = null, a referência forte ainda existe, evitando a realocação de memória ao adicionar elementos em chamadas subsequentes para add () e outros métodos. O uso de métodos como o método clear () para liberar memória é particularmente aplicável aos tipos de referência armazenados na matriz, de modo que a memória possa ser liberada a tempo.


2. Referência suave (SoftReference)

        Se um objeto tiver apenas referências suaves, o espaço de memória é suficiente, o coletor de lixo não o recuperará; se o espaço de memória for insuficiente, a memória desses objetos será recuperada . Desde que o coletor de lixo não o colete, o objeto pode ser usado pelo programa. As referências suaves podem ser usadas para implementar caches sensíveis à memória ( mybatis SoftCache usa referências fracas, e o Mapa em ThreadLocal também usa referências suaves [para evitar vazamentos de memória] ).  

Formato de declaração de referência flexível:

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 saída:

Pode-se ver que a JVM tem memória suficiente neste momento e os objetos associados às referências soft ainda não foram recuperados .

 

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

Quando a memória é insuficiente, equivale a:

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

As referências virtuais têm aplicações importantes na prática, como o botão Voltar de um navegador. Ao pressionar voltar, o conteúdo da página da web exibida durante o backup deve ser solicitado novamente ou obtido do cache? Depende da estratégia de implementação específica.

(1) Se uma página da web for reciclada no final da navegação, ela precisa ser reconstruída quando você pressiona Voltar para visualizar a página visitada anteriormente

(2) Se você armazenar as páginas da web navegadas na memória, isso irá causar muito desperdício de memória e até mesmo causar estouro de memória

Neste momento, você pode usar referências virtuais

    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);       // 重新构建
    }

Isso resolve o problema real muito bem.

       A referência soft pode ser usada em conjunto com uma fila de referência (ReferenceQueue). Se o objeto referenciado pela referência soft for reciclado pelo coletor de lixo, a máquina virtual Java adicionará a referência soft à fila de referência associada a ele.


3. Referência fraca (WeakReference)

      A diferença entre referências fracas e referências suaves é que apenas objetos com referências fracas têm um ciclo de vida mais curto. No processo de varredura do thread do coletor de lixo na área de memória sob sua jurisdição, uma vez que um objeto com apenas referências fracas for encontrado, sua memória será recuperada independentemente de o espaço de memória atual ser suficiente . No entanto, como o coletor de lixo é um thread de baixa prioridade, os objetos que têm apenas referências fracas podem não ser encontrados rapidamente.

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

Quando o coletor de lixo verifica e coleta, é equivalente a:

    str = null;
    System.gc();

   Se este objeto for usado ocasionalmente e você quiser obtê-lo a qualquer momento quando usá-lo, mas não quiser afetar a coleta de lixo deste objeto, então você deve usar Weak Reference para lembrar este objeto.   

   O código a seguir tornará str novamente uma referência forte:

String  abc = abcWeakRef.get();

Uma referência fraca pode ser usada em conjunto com uma fila de referência (ReferenceQueue). Se o objeto referenciado pela referência fraca for coletado como lixo, a máquina virtual Java adicionará a referência fraca à fila de referência associada a ele.

Quando você quer se referir a um objeto, mas esse objeto tem seu próprio ciclo de vida, e você não quer intervir no ciclo de vida desse objeto, então você usa referências fracas.

Essa referência não terá nenhuma influência adicional no julgamento da coleta de lixo do 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);
        }
    }

O resultado final é:

    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. Referência Fantasma (PhantomReference)

     Como o nome indica, "referência virtual" nada mais é do que uma referência virtual. Ao contrário de outros tipos de referências, uma referência virtual não determina o ciclo de vida de um objeto. Se um objeto contém apenas referências fantasmas, ele é o mesmo que sem nenhuma referência e pode ser coletado pelo coletor de lixo a qualquer momento.

    As referências fantasmas são usadas principalmente para rastrear as atividades dos objetos reciclados pelo coletor de lixo. Uma diferença entre a referência virtual e a referência suave e a referência fraca é que a referência virtual deve ser usada em conjunto com a fila de referência (ReferenceQueue). Quando o coletor de lixo está prestes a recuperar um objeto, se descobrir que ele tem uma referência fantasma, ele adicionará a referência fantasma à fila de referência associada a ele antes de recuperar a memória do objeto.

 

5. Resumo

 Os níveis de referências Java 4 de alto a baixo são:

             Referência forte> Referência suave> Referência fraca> Referência fantasma

Observe a diferença entre eles na coleta de lixo por meio do diagrama:


Quando o coletor de lixo fizer a coleta, alguns objetos serão coletados e outros não. O coletor de lixo marcará os objetos sobreviventes do objeto raiz Object e, em seguida, reciclará alguns objetos inacessíveis e alguns objetos referenciados. Se você não estiver familiarizado com isso, consulte o seguinte artigo:

Portal: gerenciamento de memória Java http://blog.csdn.net/mazhimazh/article/category/1907599

Explique por meio da tabela, da seguinte forma:

Tipo de referência Hora de coleta de lixo usar Tempo de sobrevivência
Citação forte Nunca Estado geral do objeto Encerre quando a JVM parar de funcionar
Referência suave Quando a memória está baixa Cache de objetos Termina quando a memória é insuficiente
Referência fraca Durante a coleta de lixo Cache de objetos Encerrar após gc ser executado
Referência fantasma Desconhecido Desconhecido Desconhecido

 

 

 

 

 

 

Artigo de referência:

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

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

Acho que você gosta

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