Qual é a diferença entre java.lang.ref.WeakReference
e java.lang.ref.SoftReference
?
Qual é a diferença entre java.lang.ref.WeakReference
e java.lang.ref.SoftReference
?
Respostas:
From Understanding Weak References , de Ethan Nicholas:
Referências fracas
Uma referência fraca , simplificando, é uma referência que não é forte o suficiente para forçar um objeto a permanecer na memória. Referências fracas permitem que você aproveite a capacidade do coletor de lixo de determinar a acessibilidade para você, para que você não precise fazer isso sozinho. Você cria uma referência fraca como esta:
WeakReference weakWidget = new WeakReference(widget);
e depois em outro lugar no código que você pode usar
weakWidget.get()
para obter oWidget
objeto real . É claro que a referência fraca não é forte o suficiente para impedir a coleta de lixo; portanto, você pode descobrir (se não houver referências fortes ao widget) que deweakWidget.get()
repente começa a retornarnull
....
Referências suaves
Uma referência suave é exatamente como uma referência fraca, exceto que é menos ansiosa para jogar fora o objeto ao qual se refere. Um objeto que é apenas fracamente acessível (as referências mais fortes a ele são
WeakReferences
) será descartado no próximo ciclo de coleta de lixo, mas um objeto que é levemente acessível geralmente fica por um tempo.
SoftReferences
não é necessário que ele se comporte de maneira diferenteWeakReferences
, mas, na prática, objetos que são facilmente alcançáveis geralmente são mantidos enquanto a memória estiver em abundância. Isso os torna uma excelente base para um cache, como o cache de imagem descrito acima, pois você pode deixar o coletor de lixo se preocupar tanto com a acessibilidade dos objetos (um objeto altamente alcançável nunca será removido do cache) quanto com a gravidade do problema. precisa da memória que eles estão consumindo.
E Peter Kessler acrescentou em um comentário:
O Sun JRE trata as SoftReferences de maneira diferente das WeakReferences. Tentamos manter o objeto referenciado por um SoftReference se não houver pressão na memória disponível. Um detalhe: a política para os JRE "-client" e "-server" são diferentes: o JRE -client tenta manter sua pegada pequena, preferindo limpar SoftReferences em vez de expandir o heap, enquanto o JRE -server tenta manter seu alto desempenho, preferindo expandir a pilha (se possível) em vez de limpar SoftReferences. Um tamanho não serve para todos.
Referências fracas são coletadas ansiosamente. Se o GC descobrir que um objeto é fracamente acessível (acessível apenas por referências fracas), ele limpará as referências fracas a esse objeto imediatamente. Como tal, eles são bons para manter uma referência a um objeto para o qual seu programa também mantém (fortemente referenciadas) "informações associadas" em algum lugar, como informações de reflexão em cache sobre uma classe ou um invólucro para um objeto, etc. não faz sentido manter o objeto associado ao GC-ed. Quando a referência fraca é limpa, ela é enfileirada em uma fila de referência que seu código pesquisa em algum lugar, além de descartar os objetos associados. Ou seja, você mantém informações extras sobre um objeto, mas essas informações não são necessárias quando o objeto a que ele se refere desaparece. Na realidade, em determinadas situações, você pode até subclassificar WeakReference e manter as informações extras associadas sobre o objeto nos campos da subclasse WeakReference. Outro uso típico do WeakReference é em conjunto com o Maps para manter instâncias canônicas.
As SoftReferences, por outro lado, são boas para armazenar em cache recursos externos recreativos, pois o GC normalmente atrasa a limpeza. É garantido, no entanto, que todas as SoftReferences serão limpas antes da saída do OutOfMemoryError, portanto, teoricamente, elas não podem causar um OOME [*].
O exemplo típico de caso de uso é manter uma forma analisada de um conteúdo de um arquivo. Você implementaria um sistema no qual carregaria um arquivo, analisaria e manteria um SoftReference no objeto raiz da representação analisada. Da próxima vez que você precisar do arquivo, tente recuperá-lo através do SoftReference. Se você pode recuperá-lo, poupou-se de outra carga / análise e, se o GC o limpou nesse meio tempo, você o recarregou. Dessa forma, você utiliza memória livre para otimização de desempenho, mas não arrisca um OOME.
Agora para o [*]. Manter um SoftReference não pode causar um OOME em si. Se, por outro lado, você usa o SoftReference por engano para uma tarefa que um WeakReference deve ser usado (a saber, você mantém as informações associadas a um Objeto de alguma forma fortemente referenciadas e as descarta quando o objeto de Referência é limpo), você pode executar o OOME como seu código que pesquisa o ReferenceQueue e descarta os objetos associados pode não ser executado em tempo hábil.
Portanto, a decisão depende do uso - se você estiver armazenando em cache informações que são caras de construir, mas mesmo assim reconstrutíveis a partir de outros dados, use referências flexíveis - se você estiver mantendo uma referência a uma instância canônica de alguns dados ou desejar tenha uma referência a um objeto sem "possuí-lo" (impedindo-o de ser GC'd), use uma referência fraca.
WeakReference
é que, em locais onde a pessoa deve usá-la, o fato de permanecer válido por um tempo após a referência sair do escopo pode ser tolerável, mas não é desejável.
WeakReference
para observar as execuções do GC. Veja elaboração: stackoverflow.com/a/46291143/632951
Em Java ; ordem do mais forte para o mais fraco, existem: Forte, Suave, Fraco e Fantasma
Uma referência Forte é uma referência normal que protege o objeto referido da coleção pelo GC. ou seja, nunca coleta lixo.
Uma referência suave é qualificada para coleta pelo coletor de lixo, mas provavelmente não será coletada até que sua memória seja necessária. ou seja, o lixo é coletado antes OutOfMemoryError
.
Uma referência fraca é uma referência que não protege um objeto referenciado da coleção pelo GC. ou seja, o lixo é coletado quando não há referências de Forte ou Macio.
Uma referência fantasma é uma referência a um objeto que é referenciada fantasmamente após sua finalização, mas antes de sua memória alocada ter sido recuperada.
Analogia: Suponha que uma JVM é um reino, Object é um rei do reino e GC é um atacante do reino que tenta matar o rei (objeto).
until memory is available
não faz sentido. Você quer dizer is eligible for collection by garbage collector, but probably won't be collected until its memory is needed for another use
?
Referência fraca http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html
Princípio: weak reference
está relacionado à coleta de lixo. Normalmente, objeto com um ou maisreference
não será elegível para coleta de lixo.
O princípio acima não é aplicável quando é weak reference
. Se um objeto tiver apenas uma referência fraca com outros objetos, estará pronto para a coleta de lixo.
Vejamos o exemplo abaixo: Temos um Map
com objetos onde Key é referência a um objeto.
import java.util.HashMap;
public class Test {
public static void main(String args[]) {
HashMap<Employee, EmployeeVal> aMap = new
HashMap<Employee, EmployeeVal>();
Employee emp = new Employee("Vinoth");
EmployeeVal val = new EmployeeVal("Programmer");
aMap.put(emp, val);
emp = null;
System.gc();
System.out.println("Size of Map" + aMap.size());
}
}
Agora, durante a execução do programa que fizemos emp = null
. A Map
realização a chave não faz sentido aqui como é null
. Na situação acima, o objeto não é coletado como lixo.
WeakHashMap
WeakHashMap
é aquele em que as entradas (key-to-value mappings
) serão removidas quando não for mais possível recuperá-las do Map
.
Deixe-me mostrar o exemplo acima mesmo com o WeakHashMap
import java.util.WeakHashMap;
public class Test {
public static void main(String args[]) {
WeakHashMap<Employee, EmployeeVal> aMap =
new WeakHashMap<Employee, EmployeeVal>();
Employee emp = new Employee("Vinoth");
EmployeeVal val = new EmployeeVal("Programmer");
aMap.put(emp, val);
emp = null;
System.gc();
int count = 0;
while (0 != aMap.size()) {
++count;
System.gc();
}
System.out.println("Took " + count
+ " calls to System.gc() to result in weakHashMap size of : "
+ aMap.size());
}
}
Saída: levou 20 calls to System.gc()
para resultar emaMap size
: 0.
WeakHashMap
tem apenas referências fracas às chaves, não referências fortes como outras Map
classes. Há situações em que você deve tomar cuidado quando o valor ou a chave é fortemente referenciado, embora você tenha usado WeakHashMap
. Isso pode ser evitado envolvendo o objeto em um WeakReference .
import java.lang.ref.WeakReference;
import java.util.HashMap;
public class Test {
public static void main(String args[]) {
HashMap<Employee, EmployeeVal> map =
new HashMap<Employee, EmployeeVal>();
WeakReference<HashMap<Employee, EmployeeVal>> aMap =
new WeakReference<HashMap<Employee, EmployeeVal>>(
map);
map = null;
while (null != aMap.get()) {
aMap.get().put(new Employee("Vinoth"),
new EmployeeVal("Programmer"));
System.out.println("Size of aMap " + aMap.get().size());
System.gc();
}
System.out.println("Its garbage collected");
}
}
Referências suaves.
Soft Reference
é um pouco mais forte que a referência fraca. A referência suave permite a coleta de lixo, mas pede ao coletor de lixo que a limpe apenas se não houver outra opção.
O coletor de lixo não coleta agressivamente objetos de fácil acesso, como ocorre com objetos de fácil acesso - em vez disso, apenas coleta objetos de fácil acesso se realmente "precisar" da memória. Referências suaves são uma maneira de dizer ao coletor de lixo: "Enquanto a memória não estiver muito tensa, eu gostaria de manter esse objeto por perto. Mas se a memória ficar muito tensa, vá em frente e colete-a, e eu resolvo com isso." O coletor de lixo é necessário para limpar todas as referências suaves antes que ele possa ser lançado OutOfMemoryError
.
NullPointerException
no aMap.get().put(...)
.
WeakHashMap
exemplo (já que esse é o primeiro que está demonstrando comportamento fraco). Veja o documento para "WeakHashMap": "An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. "
O ponto principal de usar o WeakHashMap é que você não precisa declarar / passar um WeakReference; o WeakHashMap faz isso por você, internamente. docs.oracle.com/javase/7/docs/api/java/util/WeakHashMap.html
WeakHashMap
em ação, com o exemplo de aplicativo mostrando como as entradas são removidas somente após a execução da coleta de lixo, consulte minha Resposta à pergunta: O WeakHashMap está sempre crescendo ou limpa as chaves do lixo? .
A única diferença real entre uma referência suave e uma referência fraca é que
o coletor de lixo usa algoritmos para decidir se deve ou não recuperar um objeto de fácil acesso, mas sempre recupera um objeto de difícil acesso.
SoftReference
foi projetado para caches. Quando for descoberto que um faz WeakReference
referência a um objeto inacessível, ele será limpo imediatamente. SoftReference
pode ser deixado como está. Normalmente, existe algum algoritmo relacionado à quantidade de memória livre e ao tempo usado pela última vez para determinar se ela deve ser limpa. O algoritmo atual da Sun é limpar a referência se ela não for usada em tantos segundos quanto houver megabytes de memória livre no heap Java (configurável, o HotSpot do servidor verifica o heap máximo possível, conforme definido por -Xmx
). SoftReference
s serão limpos antes de OutOfMemoryError
serem lançados, a menos que seja alcançável de outra forma.
java.lang
. Tal abuso de sinônimos não está fazendo bem a ninguém.
Este artigo pode ser super útil para entender referências fortes, suaves, fracas e fantasmas.
Para lhe dar um resumo,
Se você tiver apenas referências fracas a um objeto (sem referências fortes), o objeto será recuperado pelo GC no próximo ciclo do GC.
Se você tiver apenas referências simples para um objeto (sem referências fortes), o objeto será recuperado pelo GC somente quando a JVM ficar sem memória.
Então, você pode dizer que referências fortes têm o poder máximo (nunca podem ser coletadas pelo GC)
Referências suaves são poderosas que referências fracas (pois podem escapar do ciclo do GC até a JVM ficar sem memória)
Referências fracas são ainda menos poderosas que as referências flexíveis (como não podem exceder nenhum ciclo do GC e serão recuperadas se o objeto não tiver outra referência forte).
Analogia do restaurante
Agora, se você é um cliente forte (referência análoga a forte), mesmo que um novo cliente chegue ao restaurante ou o que quer que seja, nunca sairá da sua mesa (a área de memória na pilha). O garçom não tem o direito de pedir para você (ou até mesmo solicitar) para sair do restaurante.
Se você é um cliente flexível (semelhante à referência suave), se um novo cliente entrar no restaurante, o garçom não solicitará que você saia da mesa, a menos que não haja outra mesa vazia para acomodar o novo cliente. (Em outras palavras, o garçom solicitará que você saia da mesa apenas se um novo cliente entrar e não houver outra mesa para esse novo cliente)
Se você é um cliente fraco (referência análoga a fraca), o garçom, por sua vontade, pode (a qualquer momento) pedir para você sair do restaurante: P
De acordo com o documento , as WeakReferences frouxas devem ser limpas por um GC em execução.
De acordo com o documento , as SoftReferences soltas devem ser limpas antes que o OOM seja lançado.
Essa é a única diferença real. Tudo o resto não faz parte do contrato. (Presumo que os documentos mais recentes sejam contratuais.)
SoftReferences são úteis. Os caches sensíveis à memória usam SoftReferences, não WeakReferences.
weak_ref.get()
. Quando é null
, você aprende que, entre essa duração, o GC foi executado.
Quanto ao uso incorreto do WeakReference, a lista é interminável:
um truque ruim para implementar a softreferência de prioridade 2, de modo que você não precise escrever uma, mas não funciona conforme o esperado, porque o cache seria limpo a cada execução do GC, mesmo quando houver memória disponível. Consulte https://stackoverflow.com/a/3243242/632951 para obter phails. (Além disso, e se você precisar de mais de 2 níveis de prioridade de cache? Você ainda precisará de uma biblioteca real para isso.)
um péssimo hack para associar dados a um objeto de uma classe existente, mas cria um vazamento de memória (OutOfMemoryError) quando o seu GC decide fazer uma pausa após a criação de suas fracas referências. Além disso, é muito feio: uma abordagem melhor é usar tuplas.
um truque ruim para associar dados a um objeto de uma classe existente, em que a classe tem a coragem de se tornar não subclassável e é usada em um código de função existente que você precisa chamar. Nesse caso, a solução adequada é editar a classe e torná-la subclassável, ou editar a função e fazer com que ela use uma interface em vez de uma classe ou use uma função alternativa.
equals()
é apenas identidade do objeto? Referências suaves parecem um desperdício lá, porque uma vez que um objeto-chave não é mais alcançável, ninguém mais procurará esse mapeamento.
Os seis tipos de estados de acessibilidade de objetos em Java:
Para mais detalhes: https://www.artima.com/insidejvm/ed2/gc16.html «recolher
Deve-se estar ciente de que um objeto com pouca referência só será coletado quando tiver APENAS referências fracas. Se tiver apenas uma referência forte, ele não será coletado, não importa quantas referências fracas tenha.
Para dar um aspecto de uso da memória em ação, fiz um experimento com referências Forte, Suave, Fraca e Fantasma sob carga pesada com objetos pesados, mantendo-as até o final do programa. Em seguida, monitorou o uso de heap e o comportamento do GC . Essas métricas podem variar caso a caso, mas certamente oferecem um alto nível de entendimento. Abaixo estão os resultados.
Heap e comportamento do GC sob carga pesada
Você pode obter gráficos mais detalhados , estatísticas, observações para este experimento aqui .
WeakReference : objetos que são pouco referenciados são coletados a cada ciclo do GC (menor ou completo).
SoftReference : quando objetos que são apenas referenciados suavemente são coletados depende de:
-XX: SoftRefLRUPolicyMSPerMB = N sinalizador (o valor padrão é 1000, ou seja, 1 segundo)
Quantidade de memória livre na pilha.
Exemplo:
O objeto referenciado apenas pelo SoftReference será coletado se a última vez em que foi acessada for maior que 10 segundos.