O que você sabe sobre WeakReferences? Pouco, muito pouco, nada? Parte significativa da comunidade de desenvolvedores não conhece ou nunca utilizou esse recurso para desenvolver suas aplicações. Apesar de ser um mecanismo implementado por varias linguagens – C#, Java, Python, Lua, dentre outras – essa ainda é pouco utilizado e não se conhece muito sobre como se beneficiar de sua aplicação.

Primeiro vamos entender o que são WeakReferences, ou “referencias fracas” em uma tradução ao pé da letra.

 CHAMPOLIM MEME PRONTO

Primeiros passos

Como sabemos, em linguagens como C# e Java, toda variável que criamos é na verdade uma referência para um espaço de memória que, após alocado, pode ser referenciado por mais variáveis. Sabemos também que linguagens como essas utilizam de um mecanismo que de tempos em tempos libera a memória alocada anteriormente quando essa não é mais referenciada. Essas variáveis são do tipo StrongReference, ou seja, elas não deixam que o mecanismo de limpeza (Garbage Collector) libere aquele espaço de memória enquanto existirem.

Referências fracas são exatamente o oposto das variáveis convencionais que conhecemos. Quando se cria uma WeakReference, cria-se uma variável que permite ao Garbage Collector liberar a memória quando bem entender. Se o espaço de memória alocado só tem referências fracas, ele pode existir em um instante e não existir no instante seguinte. Uma característica visível aqui é a não preocupação com o gerenciamento de memória utilizada com essas variáveis, já que o coletor irá cuidar de tudo. Essa característica não deve ser considerada até aqui como vantajosa ou desvantajosa, deve ser trabalhada para se tornar útil, pois sua má utilização pode acarretar sérios problemas.

Para entendermos essa preocupação consideremos o código a seguir:

andregui1

 

No código acima vemos uma situação típica de um possível erro ao utilizar WeakReferences. Foi instanciada uma WeakReference (ReferênciaFraca) e em seguida atribuímos uma posição de memória ao seu membro Target. Essa posição de memória pode a qualquer momento ser liberada pelo coletor fazendo com que o membro Target possua valor null. Ao passo que a função toString() é chamada existe a possibilidade de ser lançada  a famosa e indesejada exceção NullPointerException.

Para utilizarmos de forma segura a WeakReference devemos implementar da maneira apresentada a seguir:

andregui2

 

Acima temos um exemplo que sempre funcionará. Quando atribuímos o valor de referênciaFraca.Target à referênciaForte podemos estar atribuindo valor null mas como estamos verificando o valor da ultima variável logo em seguida, não corremos o risco de lançar uma exceção inesperada. A variável referênciaForte não corre o risco de ter seu valor anulado a qualquer momento como da WeakReference, sendo totalmente segura.

Sejamos práticos

Se mesmo após a breve explicação do que são referencias fracas você ainda não vê como utilizar tal mecanismo de forma útil nas suas aplicações, vamos a algo mais concreto.

Muitos devem conhecer estratégias de cache. Caches são proxys que representam objetos em memória que não são desalocados assim que não são mais necessários. Contudo, a existência de muitos desses recursos pode acabar sobrecarregando a memória tornando necessário o expurgo dos objetos em um período determinado de tempo. Aplicações podem melhorar sensivelmente seu desempenho ao manter essas estruturas residindo em memória.

No entanto para se utilizar dessa abordagem deve-se ater a duas coisas: ou o cache pode crescer indefinidamente, o que na maioria das aplicações é intolerável, ou ser implementado um mecanismo explicito de gerenciamento de cache, o qual pode levar muito código para resolver o problema.

Utilizando-se de referencias fracas é possível criar estratégias de cache autogeridas. Por exemplo, considere uma aplicação que armazene milhões de dados de tabela, banco de dados, em um result set. Os dados são carregados em WeakReferences  (cache) que serão referenciadas por StrongReferences sempre que necessário. Ao passo que só existirem referencias fracas para os dados armazenados, ficará a cargo do coletor liberar ou não esses objetos. Sempre que essas informações forem necessárias deve-se verificar se a WeakReference ainda contém aquele dado, caso contrário é feita uma nova busca no banco de dados.

Conclusão

O exemplo acima foi apenas uma ideia do que podemos fazer utilizando WeakReferences, ou referencias fracas. Muito ainda pode ser explorado e aperfeiçoado com essa abordagem, mas é preciso tomar cuidado! Como vimos, o uso deve ser consciente e seguro. Não ter pleno controle sobre uma variável pode carretar muita dor de cabeça.

 

Por: André Guimarães
Revisão: Jéssica Saliba

Deixe um comentário