Referências fantasmas em Java

Referências fantasmas em Java

1. Visão geral

Neste artigo, daremos uma olhada no conceito de Referência Fantasma - na linguagem Java.

2. Referências fantasmas

As referências fantasmas têm duas diferenças principais das referênciassofteweak.

We can’t get a referent of a phantom reference. O referente nunca está acessível diretamente através da API e é por isso que precisamos de uma fila de referência para trabalhar com este tipo de referências.

O Coletor de lixo adiciona uma referência fantasma a uma fila de referênciaafter the finalize method of its referent is executed. Isso implica que a instância ainda está na memória.

3. Casos de Uso

Existem dois casos de uso comuns para os quais eles são usados.

A primeira técnica éto determine when an object was removed from the memory, que ajuda a agendar tarefas sensíveis à memória. Por exemplo, podemos esperar que um objeto grande seja removido antes de carregar outro.

A segunda prática éto avoid using the finalize method and improve thefinalization process.

3.1. Exemplo

Agora, vamos implementar o segundo caso de uso para descobrir praticamente como esse tipo de referência funciona.

Primeiro, precisamos de uma subclasse da classePhantomReference para definir um método para limpar recursos:

public class LargeObjectFinalizer extends PhantomReference {

    public LargeObjectFinalizer(
      Object referent, ReferenceQueue q) {
        super(referent, q);
    }

    public void finalizeResources() {
        // free resources
        System.out.println("clearing ...");
    }
}


Agora, vamos escrever uma finalização aprimorada de granulação fina:

ReferenceQueue referenceQueue = new ReferenceQueue<>();
List references = new ArrayList<>();
List largeObjects = new ArrayList<>();

for (int i = 0; i < 10; ++i) {
    Object largeObject = new Object();
    largeObjects.add(largeObject);
    references.add(new LargeObjectFinalizer(largeObject, referenceQueue));
}

largeObjects = null;
System.gc();

Reference referenceFromQueue;
for (PhantomReference reference : references) {
    System.out.println(reference.isEnqueued());
}

while ((referenceFromQueue = referenceQueue.poll()) != null) {
    ((LargeObjectFinalizer)referenceFromQueue).finalizeResources();
    referenceFromQueue.clear();
}


Primeiro, estamos inicializando todos os objetos necessários:referenceQueue - para manter o controle das referências enfileiradas,references - para realizar o trabalho de limpeza depois,largeObjects - para imitar uma grande estrutura de dados.

A seguir, estamos criando esses objetos usando as classesObjecteLargeObjectFinalizer.

Antes de chamarmos o Garbage Collector, liberamos manualmente uma grande parte dos dados desreferenciando a listalargeObjects. Observe que usamos um atalho para a instruçãoRuntime.getRuntime().gc() para invocar o Coletor de Lixo.

É importante saber queSystem.gc() não está acionando a coleta de lixo imediatamente - é simplesmente uma dica para a JVM acionar o processo.

O loopfor demonstra como ter certeza de que todas as referências estão enfileiradas - ele imprimirátrue para cada referência.

Finalmente, usamos um loopwhile para pesquisar as referências enfileiradas e fazer o trabalho de limpeza para cada uma delas.

4. Conclusão

Neste tutorial rápido, apresentamos as referências fantasmas do Java.

Aprendemos o que são e como podem ser úteis em alguns exemplos simples e direto ao ponto.