Слабая ссылка на объект 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();
            }
        }
    }
}

Если использовать 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.

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);
    }
}
  • works/programmer/java/weak-reference.txt
  • Последнее изменение: 2025/11/22 01:52
  • Eugene