Слабая ссылка на объект WeakReference
Основной концепт
Простенкий пример кода который показывает как заставить GC работать со слабыми ссылками. В отличии от Optional - WeakReference не даёт не каких гарантий что объект ещё живой.
Сам-же Optional содержит в себе сильную ссылку на объект и объект будет живой для GC пока живой Optional.
MyObj obj = new MyObj(); WeakReference<MyObj> ref = new WeakReference<>(obj); obj = null; // нет сильных ссылок MyObj local = ref.get(); // теперь есть сильная ссылка снова! local.doSomething(); // можно использовать System.gc(); // GC НЕ тронет объект local = null; // убрали последнюю сильную ссылку System.gc(); // теперь объект можно удалить
Таймер привязанный к объекту
Простенький пример: таймер который живой пока живой объект.
Если объект стал недостижим (GC готов удалить), таймер прекращается.
import java.lang.ref.WeakReference; import java.util.concurrent.*; public class AliveTimer { private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); public void start(Object target) { WeakReference<Object> ref = new WeakReference<>(target); scheduler.scheduleAtFixedRate(() -> { if (ref.get() == null) { System.out.println("Object is gone. Stopping timer..."); scheduler.shutdown(); } else { System.out.println("Object still alive"); } }, 0, 1, TimeUnit.SECONDS); } } AliveTimer timer = new AliveTimer(); Object obj = new Object(); timer.start(obj); // через некоторое время: obj = null; System.gc();
Список возможно живых объектов
public interface Listener { void onEvent(); } public class EventSource { private final List<WeakReference<Listener>> listeners = new ArrayList<>(); public void addListener(Listener l) { listeners.add(new WeakReference<>(l)); } public void fire() { for (Iterator<WeakReference<Listener>> it = listeners.iterator(); it.hasNext();) { Listener l = it.next().get(); if (l == null) { it.remove(); // слушатель умер — чистим } else { l.onEvent(); } } } }
Слабый хешмап - WeakHashMap
Если использовать HashMap — данные будут жить вечно, так как содержит сильные ссылки. Если WeakHashMap — ключи исчезают, когда на них нет сильных ссылок.
Map<Object, String> cache = new WeakHashMap<>(); public String compute(Object key) { return cache.computeIfAbsent(key, k -> heavyWork(k)); }
Другие классы работающие в этой теме
WeakReference — как память про картинку в кеше
- Хочешь — используй.
- Не хочешь — GC выбросит.
SoftReference — как закладка в браузере
- Если есть память — оставлю.
- Если нет — удалю.
PhantomReference — как уведомление из морга
- «Поступил труп, можешь приходить и забирать свои ресурсы».
Немножко PhantomReference
Таймер привязанный к объекту, живущий через PhantomReference.
import java.lang.ref.*; import java.util.concurrent.*; public class PhantomTimer { private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); public void start(Object target) { ReferenceQueue<Object> queue = new ReferenceQueue<>(); PhantomReference<Object> phantom = new PhantomReference<>(target, queue); executor.scheduleAtFixedRate(() -> { Reference<?> ref = queue.poll(); if (ref != null) { System.out.println("Object collected. Stopping timer."); executor.shutdown(); } else { System.out.println("Object alive."); } }, 0, 1, TimeUnit.SECONDS); } }