Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Типы ссылок в Java
В Java есть 4 основных типа ссылок на объекты, которые влияют на поведение garbage collector. Они классифицируются по силе привязки объекта к памяти.
1. Strong Reference (Сильная ссылка)
Это обычная ссылка, которую ты используешь каждый день. Пока есть хоть одна strong reference на объект, GC не удалит его.
public class StrongReferenceExample {
public static void main(String[] args) {
Person person = new Person("John"); // Strong reference
System.out.println(person.getName()); // John
person = null; // Теперь нет strong references, объект может быть удалён GC
}
}
List<String> list = new ArrayList<>(); // Strong reference на список
list.add("Item1"); // Объекты в списке тоже имеют strong references
Характеристики:
- Объект НЕ будет удалён GC, пока существует хоть одна strong reference
- Самый часто используемый тип
- Может привести к утечкам памяти, если забыть обнулить
2. Soft Reference (Мягкая ссылка)
Объект с soft reference удаляется GC только когда памяти МАЛО. Полезна для кешей.
import java.lang.ref.SoftReference;
public class SoftReferenceExample {
public static void main(String[] args) {
Person person = new Person("John");
SoftReference<Person> softRef = new SoftReference<>(person);
person = null; // Удалили strong reference
// softRef.get() может вернуть объект, если он ещё в памяти
Person retrieved = softRef.get(); // Может быть null, если GC удалил
if (retrieved != null) {
System.out.println("Object still in memory");
} else {
System.out.println("Object was garbage collected");
}
}
}
// Практический пример: кеш изображений
public class ImageCache {
private Map<String, SoftReference<BufferedImage>> cache = new HashMap<>();
public void putImage(String key, BufferedImage image) {
cache.put(key, new SoftReference<>(image));
}
public BufferedImage getImage(String key) {
SoftReference<BufferedImage> ref = cache.get(key);
if (ref != null) {
BufferedImage img = ref.get();
if (img != null) {
return img; // Кеш попал!
}
}
return null; // Объект был удалён GC из-за нехватки памяти
}
}
Характеристики:
- GC удалит объект только если памяти недостаточно
- Идеально для кешей (когда потеря данных лучше, чем OutOfMemoryError)
- Более "мягкая" привязка, чем strong
3. Weak Reference (Слабая ссылка)
Объект удаляется при ЛЮБОМ запуске GC, независимо от памяти. Используется для отслеживания объектов без предотвращения их сборки.
import java.lang.ref.WeakReference;
public class WeakReferenceExample {
public static void main(String[] args) throws InterruptedException {
Person person = new Person("John");
WeakReference<Person> weakRef = new WeakReference<>(person);
System.out.println("Before null: " + weakRef.get()); // John
person = null; // Удалили strong reference
System.gc(); // Принудительно вызовем GC
System.out.println("After GC: " + weakRef.get()); // null (объект удалён)
}
}
// Практический пример: WeakHashMap
WeakHashMap<String, Person> map = new WeakHashMap<>();
String key = "user1";
map.put(key, new Person("John"));
key = null; // Когда удаляется ключ, запись в map тоже будет удалена
System.gc();
// Полезно для listeners и observers
public class EventManager {
private List<WeakReference<EventListener>> listeners = new ArrayList<>();
public void subscribe(EventListener listener) {
listeners.add(new WeakReference<>(listener));
}
public void notify(Event event) {
listeners.removeIf(ref -> ref.get() == null); // Удаляем мёртвые ссылки
for (WeakReference<EventListener> ref : listeners) {
EventListener listener = ref.get();
if (listener != null) {
listener.onEvent(event);
}
}
}
}
Характеристики:
- GC удалит объект при первой же сборке (если нет strong/soft references)
- Полезна для listeners, observers, кешей которые не критичны
- WeakHashMap — полезная коллекция
4. Phantom Reference (Фантомная ссылка)
Самая слабая ссылка. Никогда не вернёт сам объект, используется для отслеживания момента, когда объект ТОЧНО удалится GC. Нужна ReferenceQueue.
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
public class PhantomReferenceExample {
public static void main(String[] args) throws InterruptedException {
ReferenceQueue<Person> queue = new ReferenceQueue<>();
Person person = new Person("John");
PhantomReference<Person> phantomRef = new PhantomReference<>(person, queue);
System.out.println("Phantom ref: " + phantomRef.get()); // ВСЕГДА null!
person = null;
System.gc();
// Проверяем очередь — была ли сборка
if (queue.poll() == phantomRef) {
System.out.println("Object was garbage collected");
// Здесь можно выполнить cleanup действия
}
}
}
// Практический пример: отслеживание ресурсов
public class ResourceTracker {
private final ReferenceQueue<MyResource> queue = new ReferenceQueue<>();
private final Set<PhantomReference<MyResource>> references = new HashSet<>();
public ResourceTracker() {
Thread cleanupThread = new Thread(() -> {
while (true) {
try {
PhantomReference<?> ref = (PhantomReference<?>) queue.remove();
references.remove(ref);
System.out.println("Resource was cleaned up");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
});
cleanupThread.setDaemon(true);
cleanupThread.start();
}
public void track(MyResource resource) {
references.add(new PhantomReference<>(resource, queue));
}
}
Характеристики:
get()ВСЕГДА возвращает null- Используется с ReferenceQueue для отслеживания финализации
- Редко используется, но мощна для resource cleanup
Сравнительная таблица
| Тип | Удаляется GC | Используется для | Пример |
|---|---|---|---|
| Strong | Никогда (если есть refs) | Обычное хранение | Person p = new Person() |
| Soft | Когда мало памяти | Кеши | Image cache, LRU cache |
| Weak | При любой GC | Listeners, observers | WeakHashMap, event system |
| Phantom | После finalize | Cleanup уведомления | Resource tracking |
Практические примеры
Кеш с SoftReference
public class SoftCache<K, V> {
private final Map<K, SoftReference<V>> cache = new HashMap<>();
public void put(K key, V value) {
cache.put(key, new SoftReference<>(value));
}
public V get(K key) {
SoftReference<V> ref = cache.get(key);
if (ref != null && ref.get() != null) {
return ref.get();
}
cache.remove(key);
return null;
}
}
Observer pattern с WeakReference
public class Subject {
private List<WeakReference<Observer>> observers = new ArrayList<>();
public void attach(Observer observer) {
observers.add(new WeakReference<>(observer));
}
public void notifyObservers(String message) {
observers.removeIf(ref -> ref.get() == null);
for (WeakReference<Observer> ref : observers) {
Observer obs = ref.get();
if (obs != null) {
obs.update(message);
}
}
}
}
Когда использовать
- Strong: Всегда по умолчанию
- Soft: Когда нужен кеш, который может потеряться, чтобы избежать OutOfMemory
- Weak: Listeners, observers, где потеря ссылки — нормальное явление
- Phantom: Очень редко, только для специального resource cleanup
Итог
Типы ссылок дают контроль над поведением GC. Strong references — основа, остальные — для специальных случаев оптимизации памяти и отслеживания объектов.