De que se trata o artigo:

É explicado o conceito por trás das referências não convencionais, sendo elas: WeakReference, SoftReference e PhantomReference. O que são, como funcionam e como podem ser utilizadas na prática? Esse artigo explica também os mecanismos da JVM que esses objetos-referência utilizam para gerenciar objetos na memória.

Em que situação o tema é útil:

Com um conhecimento mais profundo sobre o funcionamento do Garbage Collector, modelo de memória da JVM e referências fracas, o programador estará preparado para lidar com problemas como vazamento de memória por exemplo. Além de ser um instrumento a mais na caixa de ferramentas de um bom programador, saber qual tipo de referência usar pode ser um “coelho na cartola” em situações difíceis.

Resumo DevMan:

Ao programar em Java, todos nós utilizamos atribuições de variáveis a novos objetos criados, ou seja, criamos uma referência convencional ou “forte” para um objeto (também chamado de referente). Sempre que isso acontece, estamos alterando o estado do objeto no Heap e consequentemente a forma como o Garbage Collector tratará o objeto. É necessário, portanto, ter um certo conhecimento sobre o funcionamento do modelo de memória da JVM e do Garbage Collector.

Quanto ao modelo de memória da JVM, abordamos o Java Stack e o Java Heap. O Stack é dividido em três regiões: Variáveis locais, que possui uma estrutura de array indexado para armazenar parâmetros e variáveis locais de um método, Operand Stack, que possui uma estrutura de pilha para calcular resultados, e Frame Data, que é usado para guardar o estado do Java Stack. Já o Java Heap é a região da memória onde todos os objetos são criados (quando você usa o operador new).

O Garbage Collector é a ferramenta usada pela JVM para limpar a memória. Agindo no Heap, por exemplo, ele procura por objetos que não possuem referências fortes, descartando-os quando encontrados. Enquanto um objeto possuir pelo menos uma referência forte, por outro lado, o objeto não será coletado. A especificação não dita o algoritmo da JVM, mas duas técnicas bem conhecidas são Counting e Tracing.

Desde a versão 1.2 do Java, os desenvolvedores podem contar com as referências fracas, que em geral, se refere aos tipos WeakReference, SoftReference e PhantomReference, que herdam da classe abstrata Reference. Referências fracas são usadas para se referenciar a um objeto sem impactar na forma como o Garbage Collector o enxerga. Caso você tenha várias referências fracas para um objeto e esse não possua mais referências fortes, o Garbage Collector poderá coletá-lo sem problemas. Objetos de referência em seus três sabores podem ser utilizados no desenvolvimento de APIs para Event Handlers, ferramentas de debug ou até mesmo caches sensíveis à memória.

Não é algo novo. Muito pelo contrário, desde a versão 1.2 do Java, os desenvolvedores da plataforma podem contar com um instrumento a mais em sua caixa de ferramentas, que pode vir a ser muito útil para gerenciar objetos na memória – as referências fracas. O termo “referências fracas”, na verdade, se aplica aos três tipos não convencionais de referência: Weak, Soft e Phantom References. Isso significa que, além das referências comuns usadas no nosso dia-a-dia, que usam a construção Tipo variável = new Tipo(), existem outros tipos de referências que não se prendem ao objeto referenciado de maneira tão forte quanto as referências convencionais.

Muitos dizem que referências fracas são úteis apenas para desenvolver caches em memória. Na verdade, essa ferramenta também serve para esse propósito, não sendo, porém, a solução ideal para isso (como veremos). De forma geral, saber o que são e como utilizar referências fracas pode ser de grande ajuda ao manipular objetos que não podem ser referenciados de forma convencional, sob pena de causar um grande impacto na coleta de lixo da JVM e consequentemente na memória.

O entendimento correto sobre referências convencionais e não convencionais exige um bom conhecimento sobre a forma como a JVM trata objetos numa aplicação. Por esse motivo, revisamos nesse artigo alguns conceitos-chave sobre Garbage Collector e o modelo de memória da JVM, visando aumentar o conhecimento do leitor sobre o assunto. Além disso, serão analisados alguns casos onde esses objetos-referência podem ser utilizados.

Caso precise referenciar um objeto, mas não quiser alterar a forma de o Garbage Collector enxergá-lo, as referências fracas são uma solução. Isso pode acontecer em projetos onde o gerenciamento de memória e o controle sobre o estado dos objetos são fundamentais.

Modelo de memória da JVM

A Java Virtual Machine precisa de memória para guardar objetos instanciados pelo programa, variáveis locais, informações extraídas de classes e etc. Para cumprir esse objetivo, a JVM possui as chamadas “runtime data areas”, ou áreas de memória, que são: Method Area, Heap, Java Stacks, PC Registers e Native Method Stacks. Vamos nos limitar a falar sobre os Java Stacks e o Heap, visto que referências fracas abrangem apenas essas duas áreas.

Java Stacks

Sabemos que todas as aplicações em Java usam threads (pelo menos uma, o fluxo principal do programa). Por sua vez, cada thread criada possui um PC Register, que indica qual a próxima instrução a ser executada, assim como também uma pilha ou Java Stack, que guarda o estado de cada invocação feita em um método Java em forma de variáveis locais, parâmetros e valor de retorno, por exemplo. Quando dizemos “pilha”, a primeira coisa que vem a mente é a clássica estrutura de dados que funciona seguindo o protocolo de First-in First-out, ou seja, o primeiro elemento a entrar é o primeiro a sair. ...

Quer ler esse conteúdo completo? Tenha acesso completo