Quando você usaria um WeakHashMap ou um WeakReference?

O uso de referências fracas é algo que eu nunca vi uma implementação, então estou tentando descobrir qual é o caso de uso e como a implementação funcionaria. Quando você precisou usar um WeakHashMap ou WeakReference e como foi usado?

    Um problema com referências fortes é o armazenamento em cache, especialmente com estruturas muito grandes, como imagens. Suponha que você tenha um aplicativo que tenha que trabalhar com imagens fornecidas pelo usuário, como a ferramenta de design do site em que trabalho. Naturalmente, você deseja armazenar essas imagens em cache, porque carregá-las do disco é muito caro e você deseja evitar a possibilidade de ter duas cópias da imagem (potencialmente gigantesca) na memory de uma só vez.

    Como um cache de imagem deve nos impedir de recarregar imagens quando não é absolutamente necessário, você perceberá rapidamente que o cache deve sempre conter uma referência a qualquer imagem que já esteja na memory. Com referências fortes comuns, essa própria referência forçará a imagem a permanecer na memory, o que requer que você determine de alguma forma quando a imagem não é mais necessária na memory e a remova do cache, para que ela se torne elegível para garbage collection. Você é forçado a duplicar o comportamento do coletor de lixo e a determinar manualmente se um object deve ou não estar na memory.

    Compreendendo as referências fracas , Ethan Nicholas

    Uma distinção a ser esclarecida é a diferença entre um WeakReference e um SoftReference .

    Basicamente, um WeakReference será WeakReference GC-d pela JVM ansiosamente, uma vez que o object referenciado não possui referências WeakReference a ele. Um object SoftReference d, por outro lado, tenderá a ser deixado pelo coletor de lixo até que ele realmente precise recuperar a memory.

    Um cache onde os valores são mantidos dentro de WeakReference s seria bastante inútil (em um WeakHashMap , são as chaves que são fracamente referenciadas). SoftReferences são úteis para envolver os valores quando você deseja implementar um cache que pode aumentar e diminuir com a memory disponível

    Um uso comum de WeakReference e WeakHashMap em particular é para adicionar propriedades a objects. Ocasionalmente, você quer adicionar alguma funcionalidade ou dados a um object, mas a subclass e / ou a composição não são uma opção. Nesse caso, o mais óbvio seria criar um hashmap ligando o object que você deseja estender à propriedade que deseja adicionar. . então, sempre que você precisar da propriedade, basta procurá-la no mapa. No entanto, se os objects que você está adicionando propriedades tenderem a ser destruídos e criarem muito, você poderá acabar com muitos objects antigos em seu mapa, ocupando muita memory.

    Se você usar um WeakHashMap os objects deixarão o mapa assim que eles não forem mais usados ​​pelo resto do programa, que é o comportamento desejado.

    Eu tive que fazer isso para adicionar alguns dados para java.awt.Component para contornar uma mudança no JRE entre 1.4.2 e 1.5, eu poderia ter corrigido por subclassing cada componente que eu estava interessado int ( JButton , JFrame , JPanel . …) mas isso foi muito mais fácil com muito menos código.

    Outro caso útil para WeakHashMap e WeakReference é uma implementação de registro de ouvinte .

    Quando você cria algo que quer ouvir certos events, geralmente você registra um ouvinte, por exemplo

     manager.registerListener(myListenerImpl); 

    Se o manager armazenar seu listener com um WeakReference , isso significa que você não precisa remover o registro, por exemplo, com um manager.removeListener(myListenerImpl) porque ele será removido automaticamente assim que o ouvinte ou o componente que estiver segurando o listener ficar indisponível.

    É claro que você ainda pode remover manualmente seu ouvinte, mas se você não o fizer ou esquecer, ele não causará memory leaks e não impedirá que seu ouvinte seja coletado como lixo.

    Onde o WeakHashMap entra em cena?

    O registro de ouvinte que deseja armazenar os ouvintes registrados como WeakReference s precisa de uma coleção para armazenar essas referências. Não existe WeakHashSet implementação WeakHashSet na biblioteca Java padrão apenas um WeakHashMap mas podemos facilmente usar o último para “implementar” a funcionalidade do primeiro:

     Set listenerSet = Collections.newSetFromMap(new WeakHashMap()); 

    Com esse listenerSet para registrar um novo ouvinte, basta incluí-lo no conjunto e, mesmo que não seja removido explicitamente, se o listener não for mais referenciado, ele será removido automaticamente pela JVM.

    Por exemplo, se você quiser acompanhar todos os objects criados de uma determinada class. Para ainda permitir que esses objects sejam coletados como lixo, você mantém uma lista / mapa de referências fracas aos objects em vez dos próprios objects.

    Agora, se alguém pudesse explicar referências fantasmas para mim, eu ficaria feliz …

    Um uso do mundo real que eu tinha para o WeakReferences é se você tiver um único object muito grande que é raramente usado. Você não quer mantê-lo na memory quando não é necessário; mas, se outro segmento precisar do mesmo object, você não quer dois deles na memory também. Você pode manter uma referência fraca ao object em algum lugar e referências rígidas nos methods que o utilizam; quando os methods terminarem, o object será coletado.

    Este post do blog demonstra o uso de ambas as classs: Java: sincronizando em um ID . O uso é algo assim:

     private static IdMutexProvider MUTEX_PROVIDER = new IdMutexProvider(); public void performTask(String resourceId) { IdMutexProvider.Mutex mutext = MUTEX_PROVIDER.getMutex(resourceId); synchronized (mutext) { // look up the resource and do something with it } } 

    IdMutextProvider fornece objects baseados em id para sincronizar. Os requisitos são:

    • deve retornar uma referência ao mesmo object para uso simultâneo de IDs equivalentes
    • deve retornar um object diferente para diferentes IDs
    • nenhum mecanismo de liberação (os objects não são retornados para o provedor)
    • não deve vazar (objects não utilizados são elegíveis para garbage collection)

    Isso é obtido usando um mapa de armazenamento interno do tipo:

     WeakHashMap> 

    O object é chave e valor. Quando nada externo ao mapa tem uma referência difícil ao object, ele pode ser coletado como lixo. Valores no mapa são armazenados com referências rígidas, portanto, o valor deve ser empacotado em um WeakReference para evitar um memory leaks. Este último ponto é coberto no javadoc .

    Como dito acima, a referência fraca é mantida enquanto existir uma referência forte.

    Um exemplo de uso seria usar WeakReference dentro de listeners, de modo que os listeners não estejam mais ativos quando a referência principal para o object de destino desaparecer. Observe que isso não significa que o WeakReference é removido da lista de ouvintes, a limpeza ainda é necessária, mas pode ser executada, por exemplo, em horários programados. Isso também tem o efeito de evitar que o object escutado mantenha referências fortes e, eventualmente, seja uma fonte de inchaço de memory. Exemplo: Componentes da GUI Swing referindo-se a um modelo que possui um ciclo de vida mais longo que a janela.

    Enquanto brincávamos com ouvintes como descrito acima, percebemos rapidamente que os objects são coletados “imediatamente” do ponto de vista do usuário.

    Eu fiz uma pesquisa no Google por “new WeakHashMap ()”.

    Eu tenho um monte de jogos do projeto de caminho de class GNU e

    1. Projeto xbean do Apache: WeakHashMapEditor.java
    2. Projeto Apache Lucene: CachingWrapperFilter.java

    Você pode usar o weakhashmap para implementar um cache livre de resources para criação de objects expansivos.

    mas note que não é desejável ter objects mutáveis. Eu usei para armazenar em cache os resultados da consulta (que levam cerca de 400 ms para executar) para um mecanismo de pesquisa de texto, que raramente é atualizado.