← Назад к вопросам
Как определить объекты, подлежащие удалению сборщиком мусора?
1.7 Middle🔥 161 комментариев
#JVM и управление памятью
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Определение объектов для удаления сборщиком мусора
Сборщик мусора (Garbage Collector) использует различные алгоритмы для определения объектов, которые больше не используются. Основной подход — анализ достижимости объектов.
Концепция Reachability (Достижимость)
Объект подлежит удалению, если он недостижим из корневых ссылок (root references). Корневыми ссылками являются:
// 1. Локальные переменные в активных потоках
public void method() {
Object obj = new Object(); // obj является корневой ссылкой
// obj достижим в этом методе
} // после выхода из метода obj может быть удалён
// 2. Статические переменные класса
public class DataHolder {
public static List<String> data = new ArrayList<>(); // всегда достижима
}
// 3. Активные потоки
Thread thread = new Thread(() -> {
Object obj = new Object(); // достижим через поток
});
// 4. Объекты в памяти JVM (классы, монитор locks)
public class Monitor {
synchronized void method() { // монитор объекта достижим
// ...
}
}
Алгоритмы определения недостижимых объектов
1. Mark and Sweep (Пометь и очисти)
Самый распространённый алгоритм:
// Фаза Mark (Пометка)
public class MarkAndSweep {
// Обходим граф объектов, помечая достижимые
private void markReachable(Object obj, Set<Object> marked) {
if (marked.contains(obj)) return;
marked.add(obj);
// Рекурсивно помечаем все ссылаемые объекты
for (Object reference : obj.getReferences()) {
markReachable(reference, marked);
}
}
// Фаза Sweep (Очистка)
private void sweep(Set<Object> marked) {
for (Object obj : allObjects) {
if (!marked.contains(obj)) {
delete(obj); // удаляем недостижимые объекты
}
}
}
}
Процесс:
- GC приостанавливает все потоки (Stop The World)
- Обходит все объекты, достижимые из root references
- Помечает их как живые
- Удаляет все непомеченные объекты
- Возобновляет работу потоков
2. Generational Hypothesis
Модель поколений основана на предположении, что молодые объекты часто умирают:
public class GenerationalGC {
// Young Generation — часто сканируется
private void minorGC() {
// GC часто проверяет молодое поколение
Object young = new Object(); // создан в Young Gen
// используется...
// удаляется при Minor GC
}
// Old Generation — редко сканируется
private void majorGC() {
Object old = new Object();
// пережил несколько Minor GC
// переместился в Old Gen
// удаляется при Major GC (реже)
}
}
3. Reference Counting (менее часто используется)
public class RefCountExample {
// Каждый объект имеет счётчик ссылок
static class RefCountedObject {
int refCount = 0; // количество ссылок
void addRef() {
refCount++;
}
void removeRef() {
refCount--;
if (refCount == 0) {
delete(this); // удаляем, когда нет ссылок
}
}
}
}
Практический пример
public class GCExample {
static class Node {
Node next;
String data;
Node(String data) {
this.data = data;
}
}
public static void main(String[] args) {
// 1. Создаём объекты (достижимы)
Node node1 = new Node("First");
Node node2 = new Node("Second");
node1.next = node2;
System.out.println("Created: " + node1.data);
// 2. Удаляем ссылку (node2 всё ещё достижима через node1)
// (ничего не удаляется)
// 3. Удаляем node1 (обе цепочка становится недостижима)
node1 = null;
// node1 и node2 теперь доступны для удаления GC
// 4. В правильный момент GC удалит оба объекта
System.gc(); // явный вызов (не гарантирует выполнение)
}
}
Слабые ссылки (Weak References)
Для более гибкого контроля над GC используются слабые ссылки:
import java.lang.ref.WeakReference;
public class WeakRefExample {
static class Cache {
// Объект может быть удалён GC, даже если есть WeakReference
private Map<String, WeakReference<String>> cache = new HashMap<>();
public void put(String key, String value) {
cache.put(key, new WeakReference<>(value));
}
public String get(String key) {
WeakReference<String> ref = cache.get(key);
if (ref != null) {
String value = ref.get(); // может быть null, если GC удалил
return value;
}
return null;
}
}
}
Типы ссылок в Java:
- Strong Reference — обычные ссылки, объект не удаляется, пока на него есть strong reference
- Soft Reference — объект удаляется если память низкая
- Weak Reference — объект удаляется при следующем GC
- Phantom Reference — для cleanup операций перед удалением
Как GC определяет объект для удаления
- Нет достижимых путей от root references
- Не находится в памяти активной части программы
- Все ссылки на объект weak или phantom (при условиях)
- Нет блокировок или мониторов на объекте
Мониторинг GC
# Флаги для мониторинга
java -Xmx1024m -Xms512m \
-XX:+PrintGCDetails \
-XX:+PrintGCDateStamps \
-Xloggc:gc.log \
MyApplication
Заключение
Сборщик мусора Java автоматически отслеживает доступность объектов и удаляет недостижимые. Понимание этого процесса важно для написания эффективного кода и избегания утечек памяти через различные типы ссылок.