В какой момент происходит очистка Heap сборщиком мусора
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Очистка Heap и Garbage Collection в Java
Краткий ответ
Очистка Heap (удаление объектов, на которые нет ссылок) происходит во время GC паузы — специального момента, когда JVM приостанавливает выполнение приложения, запускает сборщик мусора, и затем возобновляет работу.
Когда именно запускается GC
Гарбадж Коллектор запускается в следующих случаях:
1. Когда Heap переполняется
Основная причина — недостаточно памяти для выделения нового объекта
public class GCTrigger {
public static void main(String[] args) {
List<byte[]> list = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
byte[] arr = new byte[1024 * 1024]; // 1 MB
list.add(arr);
// JVM начинает раздумывать о GC если Heap заканчивается
}
}
}
2. Явный вызов System.gc()
System.gc(); // просьба к JVM запустить GC (но это не гарантия!)
Важно: System.gc() — это только suggestion, а не команда. JVM может его проигнорировать.
3. Периодически (в зависимости от GC алгоритма)
Некоторые сборщики мусора работают по расписанию (например, G1GC).
Как происходит очистка (Mark-Sweep-Compact)
Фаза 1: Mark (Пометка)
GC идентифицирует объекты, на которые ещё есть ссылки:
public class ObjectReferences {
public static void main(String[] args) {
String active = "I'm alive"; // ссылка есть → будет помечен
String garbage = new String("I'll be GC'd");
garbage = null; // ссылка удалена → без пометки
// Когда запустится GC:
// - active будет помечен как "живой"
// - garbage будет помечен как "мусор"
}
}
Фаза 2: Sweep (Удаление)
Удаляются объекты без ссылок:
До GC: [obj1][obj2_garbage][obj3][obj4_garbage][obj5]
Mark: ✓ ✗ ✓ ✗ ✓
После: [obj1][obj3][obj5]
Фаза 3: Compact (Дефрагментация)
Оставшиеся объекты сдвигаются, чтобы избежать фрагментации:
// Это бывает не в очень сборщике (например, CMS skip compact)
public class CompactionExample {
// До: [obj1_small] [gap] [obj2] [gap] [obj3]
// После: [obj1] [obj2] [obj3] [free_space_for_allocation]
}
GC Pause
Во время сборки мусора всё приложение останавливается:
Время обычно: 1-100ms (зависит от количества мусора и размера Heap)
Примечание: это критично для низколатентных систем (трейдинг, реалтайм)
public class GCPauseMeasure {
public static void main(String[] args) throws Exception {
long start = System.nanoTime();
// создаём мусор
List<byte[]> trash = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
trash.add(new byte[1024]);
}
trash.clear();
// GC может запуститься здесь (pause)
Thread.sleep(100); // имитируем работу
long elapsed = System.nanoTime() - start;
System.out.println("Elapsed: " + elapsed);
}
}
Разные сборщики мусора и их поведение
Serial GC
Откл: -XX:+UseSerialGC
Процесс: Single-threaded, паузы могут быть долгие
Parallel GC (default до Java 9)
Откл: -XX:+UseParallelGC
Процесс: Multi-threaded Mark-Sweep-Compact
Оптимизация: для throughput (пропускная способность)
G1GC (default с Java 9)
Откл: -XX:+UseG1GC
Процесс: Incremental, разбивает Heap на регионы
Оптимизация: низколатентные паузы (predictable latency)
ZGC / Shenandoah (Java 15+)
Откл: -XX:+UseZGC / -XX:+UseShenandoahGC
Процесс: Concurrent (не останавливает приложение полностью)
Оптимизация: ultra-low latency, до 10ms паузы
Мониторинг GC
# Включить логирование GC
java -Xlog:gc* MyApp
# Или старый стиль
java -XX:+PrintGCDetails -XX:+PrintGCTimeStamps MyApp
Лучшие практики для минимизации GC
// 1. Избегай создания излишних объектов
public class ObjectCreation {
// ❌ Плохо — создаёт объект в каждом вызове
public String buildString(String a, String b) {
return new String(a + b); // новый объект!
}
// ✅ Хорошо
public String buildString(String a, String b) {
return a.concat(b); // может быть оптимизировано
}
}
// 2. Используй Object Pool для критичных операций
public class ObjectPool {
private Queue<ByteBuffer> pool = new LinkedList<>();
public ByteBuffer acquire() {
return pool.poll() != null ? pool.poll() : ByteBuffer.allocate(1024);
}
public void release(ByteBuffer buffer) {
buffer.clear();
pool.offer(buffer);
}
}
// 3. Правильно задавай Heap размер
// -Xms1024m -Xmx1024m (одинаковый размер = меньше пауз)
Вывод
Очистка Heap происходит во время GC паузы, которая запускается когда:
- Heap переполняется
- Явный вызов System.gc()
- По расписанию (зависит от GC алгоритма)
В этот момент JVM:
- Останавливает приложение
- Помечает живые объекты (Mark)
- Удаляет мусор (Sweep)
- Дефрагментирует память (Compact)
- Возобновляет работу
Для латентно-критичных приложений используй современные сборщики (ZGC, Shenandoah).