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

Что происходит с приложением когда Garbage Collector нужно удалить память

1.0 Junior🔥 141 комментариев
#JVM и управление памятью#Основы Java

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

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

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

Что происходит с приложением во время Garbage Collection

Краткий ответ

Когда Garbage Collector (GC) работает, приложение временно останавливается (выполняется Stop The World пауза). В это время:

  • Все потоки приложения приостанавливаются
  • JVM анализирует и удаляет недостижимые объекты
  • После завершения GC потоки возобновляют работу
  • Пользователь заметит задержку в ответе приложения

Этапы Garbage Collection

1. Mark (Пометка)

JVM сканирует всё приложение и помечает живые объекты:

┌─────────────────────────────────────┐
│ Heap Memory                         │
│  ┌────┐  ┌────┐  ┌────┐  ┌────┐   │
│  │ A  │→ │ B  │→ │ C  │  │ D  │   │
│  └────┘  └────┘  └────┘  └────┘   │
│   ✓ живой  ✓ живой  ✓ живой  ✗ мёртвый
└─────────────────────────────────────┘
public class GCDemo {
    public static void main(String[] args) {
        // На момент GC:
        Object obj1 = new Object();      // Помечается как живой (есть ссылка)
        Object obj2 = new Object();
        Object obj3 = new Object();      // Помечается как мёртвый (нет ссылки)
        obj3 = null;                     // Разорвали связь
        
        System.gc();  // Вызов GC
        // obj3 будет удалён
    }
}

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

GC удаляет помеченные мёртвые объекты и освобождает память.

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

Nекоторые GC-алгоритмы уплотняют памяти, перемещая живые объекты вместе.

Stop The World Пауза

Время ─────────────────────────────────────────────────→

│ Приложение │ GC Pause │ Приложение │ GC Pause │ Приложение │
│ работает   │ СТОП     │ работает   │ СТОП     │ работает   │
└────────────┴──────────┴───────────┴──────────┴───────────┘
    1сек       0.5сек     2сек      0.3сек      ...

Влияние на приложение

1. GUI приложения (Desktop)

// UI замораживается во время GC
public class UIApp extends JFrame {
    public UIApp() {
        setSize(400, 300);
        setVisible(true);
    }
    
    // Во время GC паузы все действия игнорируются
    // Клик кнопки может не обработаться
    // Экран может "затормозить"
}

2. Web приложения (Spring Boot)

@RestController
public class UserController {
    @GetMapping("/api/users/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        // Если GC произойдёт во время обработки запроса,
        // ответ задержится на время паузы GC
        // Клиент получит задержку в ответе
        User user = userService.findById(id);
        return ResponseEntity.ok(user);
    }
}

// Если GC пауза = 500ms, то ответ задержится на 500ms
// Для real-time приложений это может быть критично

3. Real-time системы

// Торговля на бирже, высокочастотный трейдинг
public class HighFrequencyTrade {
    public void executeTrade() {
        // GC пауза в 100ms может означать потерю миллионов!
        long startTime = System.nanoTime();
        
        // Если GC сработает здесь...
        // даже 10ms паузы = потеря возможности
        
        long endTime = System.nanoTime();
        System.out.println("Trade executed in " + (endTime - startTime) + " ns");
    }
}

Типы GC и их влияние на приложение

1. Minor GC (сборка молодого поколения)

Пауза: 1-10ms (обычно короткая)

Частота: каждые несколько секунд
Влияние: минимальное
// Быстро создаём много временных объектов
public void minorGCExample() {
    for (int i = 0; i < 1_000_000; i++) {
        String temp = "Object " + i;  // Создание в Young Generation
        // Minor GC сработает несколько раз
        // Это быстро, паузы ~5ms
    }
}

2. Major GC / Full GC (сборка всей памяти)

Пауза: 100-5000ms (очень долгая!)

Частота: редко
Влияние: критическое для некоторых приложений
// Множество долгоживущих объектов
public class FullGCExample {
    private List<byte[]> cache = new ArrayList<>();
    
    public void fillMemory() {
        for (int i = 0; i < 10_000; i++) {
            cache.add(new byte[100_000]);  // 1GB памяти
        }
        // Full GC может произойти и длиться несколько секунд!
    }
}

Мониторинг GC паузы

public class GCMonitor {
    
    public static void main(String[] args) {
        // Запуск с параметром: -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
        
        // Логи GC покажут:
        // [GC pause (G1 Humongous Allocation) 1234.567: 1.234 secs]
        //             ↑ что произошло        ↑ длительность паузы
    }
    
    // Или программно
    public void monitorGC() {
        MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
        List<GarbageCollectorMXBean> gcBeans = 
            ManagementFactory.getGarbageCollectorMXBeans();
        
        for (GarbageCollectorMXBean gcBean : gcBeans) {
            System.out.println(gcBean.getName() + ": " + 
                             gcBean.getCollectionCount() + " сборок");
            System.out.println("Total time: " + 
                             gcBean.getCollectionTime() + " ms");
        }
    }
}

Параметры JVM для управления GC

# Выбор GC алгоритма
-XX:+UseG1GC              # G1GC (рекомендуется для новых приложений)
-XX:+UseZGC              # ZGC (очень низкие паузы, Java 15+)
-XX:+UseConcMarkSweepGC  # CMS (устаревший)

# Размер памяти
-Xms2G -Xmx4G            # Min/Max heap size

# Максимальная пауза
-XX:MaxGCPauseMillis=200 # Целевая пауза 200ms (G1GC попытается)

# Логирование GC
-Xlog:gc*:file=gc.log:time,uptime,level,tags

Практические рекомендации

  • Для low-latency приложений используйте ZGC или Shenandoah GC (паузы < 10ms)
  • Избегайте создания ненужных объектов — меньше работы для GC
  • Мониторьте GC логи в production
  • Устанавливайте правильный размер heap (не слишком большой, не слишком маленький)
  • Помните о cost of GC при выборе архитектуры и алгоритмов
  • Профилируйте приложение для выявления "memory leaks" (объекты, которые не удаляются)
Что происходит с приложением когда Garbage Collector нужно удалить память | PrepBro