Quando você usaria um WeakHashMap ou um WeakReference?

163

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

18Coelho
fonte

Respostas:

96

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

Como um cache de imagem deve impedir a recarga de 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 memória. No entanto, com referências fortes comuns, essa referência forçará a imagem a permanecer na memória, o que exige que você determine de alguma forma quando a imagem não é mais necessária na memória e remova-a do cache, para que se torne elegível para a coleta de lixo. Você é forçado a duplicar o comportamento do coletor de lixo e determinar manualmente se um objeto deve ou não estar na memória.

Noções básicas sobre referências fracas , Ethan Nicholas

Jacob Krall
fonte
43
O SoftReferences não seria melhor nesse caso, isto é, referências que são coletadas apenas quando a memória começa a acabar.
JesperE 30/09/08
Estou um pouco confuso ... digamos que eu tenho um cache de imagem SWT. As imagens SWT precisam ser DESCARTADAS através do método dispose () para liberar os recursos SO. Se eu usar um WeakHashMap para armazená-los, mostre exatamente o GC descartará o objeto?
Marcolopes
2
@marcolopes o GC usaria um finalizador em qualquer outro objeto. Parece que o SWT não gosta quando você faz isso, então não acho que você possa gerenciar os recursos do sistema operacional com um WeakHashMap.
Jacob Krall
@marcolopes (assumirei que o seu GC garante uma chamada para finalizar antes de recuperar a memória.) Se o descarte for feito no finalizador de cache, tudo estará bem. Se descarte é algo que você deve chamar manualmente, 1) estenda a classe e coloque o descarte no finalizador ou 2) use a referência fantasma para rastrear e executar o descarte adequadamente. A opção 2 é melhor (evita bugs de ressurreição e oferece a capacidade de executar o descarte em outro encadeamento), mas a opção 1 é mais fácil de implementar sem classes auxiliares.
Pacerier 18/09/17
55

WeakReference versus SoftReference

Uma distinção a ser esclarecida é a diferença entre a WeakReferencee a SoftReference.

Basicamente, um WeakReferenceserá GC-d pela JVM ansiosamente, uma vez que o objecto não tem referenciado rígidos referências a ele. Um SoftReferenceobjeto d, por outro lado, tenderá a ser deixado pelo coletor de lixo até que ele realmente precise recuperar a memória.

Um cache em que os valores são mantidos dentro de WeakReferences seria bastante inútil (em a WeakHashMap, são as chaves que são pouco referenciadas). SoftReferencessão úteis para agrupar os valores quando você deseja implementar um cache que pode aumentar e diminuir com a memória disponível.

oxbow_lakes
fonte
4
"Um cache onde os valores são mantidos dentro de WeakReferences seria bastante inútil" Eu discordo totalmente.
Thomas Eding
5
@ trinithis - erm, eu realmente não sei o que dizer. Por que um cache cujos valores desaparecem no momento em que você não os está referenciando é algo útil , exatamente?
precisa saber é o seguinte
4
Para algo como memorização, um cache que armazene livremente seus valores em cache pode ser útil.
Thomas Eding
5
@ThomasEding Eu ainda não entendi. A única vez que um cache parece útil é quando não há outras referências a ele ... Se você tem referências a ele, para que precisa de um cache?
Cruncher
2
@ThomasEding, o Softref diz ao ambiente "armazene isso até que você não tenha memória". O Weakref diz ao ambiente "armazene isso até que o GC seja executado". Francamente, não há nenhum caso de uso para a refração fraca, a menos que você esteja depurando / criando um perfil do próprio GC. Se você deseja um cache sensível à memória, use softref. Se você não deseja um cache, não o armazene em cache! Onde entra o fracoref?
Pacerier 18/09/17
30

Um uso comum de WeakReferences e WeakHashMaps, em particular, é para adicionar propriedades a objetos. Ocasionalmente, você deseja adicionar alguma funcionalidade ou dados a um objeto, mas a subclasse e / ou composição não são uma opção. Nesse caso, a coisa mais óbvia a ser feita é criar um mapa de hash vinculando o objeto que você deseja estender à propriedade que deseja adicionar. . sempre que precisar da propriedade, basta procurar no mapa. No entanto, se os objetos aos quais você está adicionando propriedades tendem a ser destruídos e criados muito, você pode acabar com muitos objetos antigos em seu mapa, ocupando bastante memória.

Se você usar um, WeakHashMapos objetos sairão do seu mapa assim que não forem mais usados ​​pelo resto do seu programa, que é o comportamento desejado.

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

Lucas
fonte
1
como o WeakHashMap sabe "eles não são mais usados ​​pelo restante do seu programa"?
Vinoth Kumar CM
2
Um hasmap fraco usa referências fracas para suas chaves. Quando um objeto é referenciado apenas por referências fracas, o coletor de lixo 'notifica' o proprietário da referência fraca (nesse caso, o WeaHashMap). Gostaria de ler sobre WeakReferences e ReferenceQueues nos javadocs para entender como esses objetos interagem com o coletor de lixo.
27611 luke
1
obrigado luke, você pode fornecer um código simples para você obter a descrição?
boiledwater
Portanto, a referência fraca só faz sentido em Java devido à API peculiar do Java, em que algumas classes não podem ser estendidas.
Pacerier 18/09/17
22

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

Quando você cria algo que deseja ouvir determinados eventos, geralmente registra um ouvinte, por exemplo

manager.registerListener(myListenerImpl);

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

É claro que você ainda pode remover manualmente o ouvinte, mas se você não o esquecer ou esquecer, isso não causará vazamento de memória e não impedirá que o ouvinte seja coletado de lixo.

Onde WeakHashMapentra em cena?

O registro do ouvinte que deseja armazenar ouvintes registrados como WeakReferences precisa de uma coleção para armazenar essas referências. Não há WeakHashSetimplementação na biblioteca Java padrão apenas a, WeakHashMapmas podemos facilmente usar a última para "implementar" a funcionalidade da primeira:

Set<ListenerType> listenerSet =
    Collections.newSetFromMap(new WeakHashMap<ListenerType, Boolean>());

Com isso listenerSetpara registrar um novo ouvinte, basta adicioná-lo ao conjunto e, mesmo que não seja removido explicitamente, se o ouvinte não for mais referenciado, ele será removido automaticamente pela JVM.

icza
fonte
10
O problema com o uso de fracoHashSets para a lista de ouvintes é que as instâncias de ouvintes anônimos criadas em register () serão perdidas facilmente, o que seria inesperado pelo usuário. É mais seguro manter referências mais fortes aos ouvintes dos gerentes e confiar no chamador para fazer a coisa certa.
precisa saber é o seguinte
Para implementação do registro do ouvinte: Todos os ouvintes registrados serão coletados / destruídos no próximo chute no GC? Por exemplo, ao disparar o método onSomethingHappened () de todos os ouvintes, o que acontece se o GC for acionado?
blackkara
@icza, não acredito que as pessoas ainda estão vendendo esse mito. Esta é uma resposta completamente errada. Você também pode dizer que outro caso útil WeakHashMapé quando você precisa HashMapde alguns objetos. Então wow você não tem que fazer manualmente hashmap.remove nunca porque os itens são automagicamente removido uma vez que o obj está fora do escopo! Literalmente mágica! Um truque mágico tão feio é um facepalm completo .
Pacerier 18/09/17
3
@ Pacerier: Eu segui seus links de outros comentários em JavaScript até aqui, e ainda não entendo por que a implementação do registro de ouvinte com o WeakMap é um mito. Por exemplo, se os clientes WebSocket devem ser vinculados a alguns ouvintes através do serviço de registro, parece lógico armazenar objetos de soquete como chaves no WeakMap (para impedir que eles parem na memória após o fechamento da conexão, digamos, por erro) e poder recuperar todos os seus ouvintes, se necessário. Então, você poderia dizer o que está exatamente errado com essa abordagem?
Danificado Organic
1
@ Pacerier Eu também não entendo sua objeção. Em um cenário de publicação-assinatura ou barramento de eventos, uma coleção de referências fracas faz todo sentido para mim. É permitido ao objeto de inscrição sair do escopo e ir para a coleta de lixo sem a necessidade de cancelar formalmente a inscrição. Esse processo de cancelamento da inscrição pode ser especialmente complicado se um objeto de terceiros for responsável pela assinatura inicial sem o conhecimento do objeto de inscrição. Uma coleção de WeakReferencesimplifica bastante a base de código e evita erros desnecessários relacionados à falha no cancelamento da assinatura. Que desvantagem?
Basil Bourque
5

Esta postagem no blog demonstra o uso de ambas as classes: Java: sincronizando em um ID . O uso é mais ou menos 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 objetos baseados em identificação para sincronização. Os requisitos são:

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

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

WeakHashMap<Mutex, WeakReference<Mutex>>

O objeto é chave e valor. Quando nada externo ao mapa tem uma referência concreta ao objeto, ele pode ser coletado como lixo. Os valores no mapa são armazenados com referências concretas , portanto, o valor deve ser agrupado em um WeakReference para evitar um vazamento de memória. Este último ponto é coberto no javadoc .

McDowell
fonte
3

Se você, por exemplo, deseja acompanhar todos os objetos criados para uma determinada classe. Para ainda permitir a coleta de lixo desses objetos, mantenha uma lista / mapa de referências fracas aos objetos, em vez dos objetos em si.

Agora, se alguém pudesse me explicar referências fantasmas, eu ficaria feliz ...

JesperE
fonte
2
Um uso: as PhantomReferences permitem determinar exatamente quando um objeto foi removido da memória. Na verdade, eles são a única maneira de determinar isso. ( weblogs.java.net/blog/enicholas/archive/2006/05/… )
Jacob Krall
Na verdade, ele não é removido até que você o apague explicitamente. "Diferentemente das referências suaves e fracas, as referências fantasmas não são automaticamente limpas pelo coletor de lixo à medida que são enfileiradas. Um objeto que pode ser acessado por referências fantasmas permanecerá assim até que todas essas referências sejam limpas ou se tornem inacessíveis".
jontro
@ Jontro, mas já foi finalizado , todos os membros se foram. Efetivamente, é um objetivo em branco. Veja stackoverflow.com/q/7048767/632951
Pacerier
3

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

Um exemplo de uso seria usar WeakReference dentro dos ouvintes, para que os ouvintes não fiquem mais ativos depois que a referência principal ao objeto de destino se for. 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 impedir que o objeto escutado mantenha fortes referências e, eventualmente, seja uma fonte de inchaço da memória. Exemplo: componentes da GUI Swing que referenciam um modelo com um ciclo de vida mais longo que a janela.

Ao brincar com os ouvintes, conforme descrito acima, rapidamente percebemos que os objetos são coletados "imediatamente" do ponto de vista do usuário.

Louis Jacomet
fonte
Obrigado resposta útil. Mas eu estou pensando, nesse caso, os ouvintes devem ser registrados (referenciados) fortemente?
blackkara
Esta resposta está completamente errada. Elaboração: stackoverflow.com/questions/154724/…
Pacerier
@Pacerier - para o WeakReferencesseu comentário está completamente errado!
2

Um uso do mundo real que eu tive para o WeakReferences é se você tiver um único objeto muito grande que raramente é usado. Você não deseja mantê-lo na memória quando não for necessário; mas, se outro encadeamento precisar do mesmo objeto, você também não deseja dois na memória. Você pode manter uma referência fraca ao objeto em algum lugar e referências concretas nos métodos que o usam; quando os métodos terminarem, o objeto será coletado.


fonte
1
Esta é uma softreference, não uma fraca referência. Veja stackoverflow.com/a/155492/632951
Pacerier
-1

você pode usar ohashashmap para implementar um cache sem recursos para criação de objetos expansiva.

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

Andreas Petersson
fonte
Você está falando de uma softreference, não de uma fraca referência. Veja stackoverflow.com/a/155492/632951
Pacerier