Diretório de artigos
referência forte
Ambos são referências fortes. Referências fortes são mais comumente usadas no desenvolvimento. Enquanto houver referências a objetos, elas não serão recicladas pelo GC
// 我们自己定义的实体通过直接new的形式都是强引用
Object obj = new Object();
referência suave
Objetos gerais não serão reciclados. Quando a memória do aplicativo estiver prestes a se esgotar -> quando o OOM estiver prestes a ocorrer, o processador de lixo irá reciclá-lo, o que pode impedir que o aplicativo fique inoperante e indisponível devido ao OOM.
SoftReference<String> ref = new SoftReference<String>("aaa");
citação fraca
Quando a referência raiz se tornar inválida, ela será reciclada quando o GC for acionado na próxima vez. Mesmo que a referência raiz seja reatribuída após a reciclagem, a referência não será restabelecida
No processo de varredura da área de memória sob sua jurisdição pelo encadeamento do coletor de lixo, uma vez que um objeto com apenas referências fracas é encontrado, sua memória será recuperada independentemente de o espaço de memória atual ser suficiente ou não.
WeakReference<String> ref = new WeakReference<String>("aaa");
示例
String str=new String("333");
WeakReference<String>ref=newWeakReference<>(str);
System.out.println(ref.get());
str=null;
System.out.println(ref.get());
System.gc(); // 手动触发一次gc
System.out.println(ref.get());
Resultado: 333 333 nulo
referência fictícia
As referências virtuais não são referências reais e não afetam a coleta de lixo normal.Quando
o coletor de lixo decidir reciclar o objeto PhantomReference, ele o inserirá no ReferenceQueue.
PhantomReference.class
public class PhantomReference<T> extends Reference<T> {
public T get() {
return null;
}
public PhantomReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
Para um objeto, essa referência é inútil, e é o mesmo que não tê-la. As referências fantasmas devem ser utilizadas em conjunto com a fila de referência, cuja função é acompanhar o processo de coleta de lixo e receber uma notificação do sistema quando o objeto for recuperado pelo coletor. Quando o coletor de lixo estiver prestes a recuperar um objeto, se descobrir que ainda possui uma referência virtual, ele adicionará essa referência virtual à fila de referências após a coleta de lixo e não destruirá completamente o objeto até que sua referência virtual associada seja retirada da fila .
Referências virtuais são frequentemente ReferenceQueue
usadas em conjunto com filas de referência
fila de referência
Fila de referência
ReferenceQueue pode ser usado com SoftReference/WeakReference/PhantomReference
refrenceQueue
Em essência, é uma lista vinculada, que garante synchronized
a segurança do encadeamento, mantém volatile
o objeto modificado head
, representa o objeto principal atual e mantém o número atual de filas
Veja como os problemas de segurança de threads são garantidos
static private class Lock {
};
private Lock lock = new Lock();
Pode-se ver que um objeto de bloqueio global é usado aqui. Este é um objeto vazio, que existe apenas como um objeto de bloqueio. Seu núcleo é apenas para bloquear remove
métodos e enqueue
métodos (entrar na fila e remover a fila)
synchronized(lock){
// ...
}
Quando chamamos remove
um método, o método será chamado para Object.wait
bloquear, e quando o gc for acionado, enqueue
o notifyAll será chamado para notificar a thread, o que não é uma operação cas, portanto tem pouco impacto na performance
O seguinte simula um cenário: quando nosso objeto é reciclado por gc, a chave de referência no mapa é removida.
public class Test {
private static ReferenceQueue<byte[]> referenceQueue = new ReferenceQueue<>();
private static int _1M = 1024 * 1024;
public static void main(String[] args) throws InterruptedException {
final Map<Object, MybObject> map = new HashMap<>();
Thread thread = new Thread(() -> {
try {
int n = 0;
MybObject k;
while (null != (k = (MybObject) referenceQueue.remove())) {
// 每次触发gc都会进来一次
System.out.println("gc:" + (++n));
map.remove(k.key);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.setDaemon(true);
thread.start();
// 创建1000个对象放入map中
for (int i = 0; i < 1000; i++) {
byte[] bytesKey = new byte[_1M];
byte[] bytesValue = new byte[_1M];
map.put(bytesKey, new MybObject(bytesKey, bytesValue, referenceQueue));
}
Thread.currentThread().join();
}
static class MybObject extends PhantomReference<byte[]> {
private Object key;
MybObject(Object key, byte[] referent, ReferenceQueue<? super byte[]> q) {
super(referent, q);
this.key = key;
}
}
}
resultado da operação
gc:1
gc:2
...
gc:792
gc:793
gc:794
Pode-se ver que não há reciclagem até que 794 sejam recuperados aqui, e os 206 objetos restantes ainda estão na memória heap e não foram liberados
Observação: o resultado não é o mesmo em todos os computadores, está relacionado ao computador, à configuração e aos parâmetros jvm, e os resultados são diferentes a cada vez
Classe de limpeza
Na figura abaixo, você pode ver que o Cleaner herda a classe de referência virtual PhantomRefrence, que é essencialmente uma Refrence.
O ReferenceHandler irá buscar continuamente o objeto de referência da lista pendente. O tipo do objeto de referência pode ser de qualquer tipo. Quando o objeto de referência é um Cleaner, o método clean do Cleaner é chamado diretamente.
O método de uso também é muito simples, passe a instância do objeto e a thread executável, e quando o objeto for reciclado, o método run do executável será acionado
Cleaner.create(this, new Runnable() {
@Override
public void run() {
}
});
Na maioria dos casos, referências fortes são usadas no desenvolvimento. Em alguns cenários de negócios especiais, outros tipos de referência também são usados no modo de desenvolvimento. É recomendável que você leia este artigo com atenção e use-o conforme apropriado.