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

Что происходит с JVM во время работы Garbage Collector

2.0 Middle🔥 281 комментариев
#JVM и управление памятью#Многопоточность

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

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

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

Что происходит с JVM во время работы Garbage Collector

Основной процесс

Garbage Collector (GC) — это механизм JVM, который автоматически управляет памятью, освобождая ее от объектов, которые больше не используются. Вот что происходит с JVM во время его работы:

Остановка приложения (Stop The World)

Самое значимое событие — остановка всех потоков приложения перед началом сборки мусора. Это называется Stop The World (STW) пауза.

// Во время GC все потоки приложения приостанавливаются
public class GCDemo {
    public static void main(String[] args) {
        Object obj1 = new Object();
        Object obj2 = new Object();
        
        // В этот момент GC может начаться
        // Все потоки приложения будут остановлены
        
        obj1 = null;  // Объект становится кандидатом на удаление
    }
}

Фазы работы Garbage Collector

1. Mark (Маркировка)

GC проходит по графу объектов, начиная с корневых ссылок (stack, static переменные, активные потоки), и помечает все достижимые объекты.

// Пример графа объектов
Object root = new Object();      // Корневая ссылка
Object child = new Object();     // Достижима из root
root = null;                     // После этого оба объекта могут быть помечены
Object orphan = new Object();    // Сразу становится недостижима

2. Sweep (Удаление)

GC проходит по памяти и удаляет объекты, которые не были помечены в фазе Mark. Затем вызывает финализаторы (если они определены).

3. Compact (Уплотнение) — опционально

Некоторые сборщики мусора (например, G1GC) сдвигают объекты в памяти, чтобы уменьшить фрагментацию.

Поколения объектов (Generational GC)

Модель кучи обычно разделена на Young Generation и Old Generation:

┌─────────────────────────────────────┐
│ Heap (куча)                         │
├─────────────────────────────────────┤
│ Young Generation (Eden + Survivor)  │  ← Малые GC часто
├─────────────────────────────────────┤
│ Old Generation                      │  ← Редкие полные GC
└─────────────────────────────────────┘

Young Generation:

  • Содержит недавно созданные объекты
  • Minor GC (молодежная сборка) работает часто и быстро
  • Объекты, пережившие несколько циклов, перемещаются в Old Generation

Old Generation:

  • Содержит долгоживущие объекты
  • Full GC (полная сборка) работает редко, но долго
  • Может привести к существенным паузам приложения

Паузы и влияние на приложение

import java.lang.*;
import java.util.concurrent.TimeUnit;

public class GCPauseMeasurement {
    public static void main(String[] args) throws InterruptedException {
        long startTime = System.currentTimeMillis();
        
        // Создание большого количества объектов
        for (int i = 0; i < 1_000_000; i++) {
            byte[] data = new byte[1024];  // Выделение памяти
        }
        
        // В этот момент может произойти GC пауза
        // Приложение замерзает на 50-200ms (зависит от настроек GC)
        
        long duration = System.currentTimeMillis() - startTime;
        System.out.println("Пауза в работе: " + duration + "ms");
    }
}

Типы сборщиков мусора

Serial GC:

  • Один поток
  • Полная остановка приложения
  • Для однопоточных приложений

Parallel GC (по умолчанию в Java):

  • Многопоточный
  • Меньше пауз за счет параллелизма
  • Лучше использует многоядерные процессоры

CMS (Concurrent Mark Sweep):

  • Параллельная маркировка
  • Минимальные паузы
  • Может привести к фрагментации

G1GC (Garbage First):

  • Предсказуемые паузы
  • Работает с большими кучами (от 4GB)
  • По умолчанию в Java 9+
// Запуск с указанием GC
// java -XX:+UseG1GC MyApplication
// java -XX:+UseSerialGC MyApplication
// java -XX:+UseParallelGC MyApplication

Мониторинг работы GC

import java.lang.management.*;

public class GCMonitoring {
    public static void main(String[] args) {
        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
        
        // Текущее использование памяти
        MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
        System.out.println("Heap used: " + heapUsage.getUsed() / (1024 * 1024) + "MB");
        System.out.println("Heap max: " + heapUsage.getMax() / (1024 * 1024) + "MB");
        
        // Информация о сборщиках мусора
        for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) {
            System.out.println("GC: " + gc.getName());
            System.out.println("Сборок: " + gc.getCollectionCount());
            System.out.println("Время сборки: " + gc.getCollectionTime() + "ms");
        }
    }
}

Лучшие практики

  1. Минимизируй создание объектов — меньше объектов = меньше GC
  2. Избегай null-ассignment в циклах — не нужен явный контроль памяти
  3. Используй StringBuilder вместо String concatenation — создает меньше временных объектов
  4. Отслеживай паузы GC — используй JVM флаги -XX:+PrintGCDetails -XX:+PrintGCDateStamps
  5. Выбери правильный GC для задачи — G1GC для больших приложений, Parallel GC для пакетной обработки

Итоговый вывод

Во время работы Garbage Collector JVM останавливает все потоки приложения, выполняет маркировку достижимых объектов, удаляет недостижимые и иногда уплотняет память. Это обеспечивает автоматическое управление памятью, но может привести к паузам, которые нужно учитывать при проектировании производительно-критичных систем.