← Назад к вопросам

Какие знаешь типы ссылок?

2.0 Middle🔥 161 комментариев
#JVM и управление памятью

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Типы ссылок в 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При любой GCListeners, observersWeakHashMap, event system
PhantomПосле finalizeCleanup уведомления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 — основа, остальные — для специальных случаев оптимизации памяти и отслеживания объектов.