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

Как увидеть из Heap Dumps ошибку в работе Garbage Collection

3.0 Senior🔥 111 комментариев
#JVM и управление памятью

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

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

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

Как увидеть из Heap Dumps ошибку в работе Garbage Collection

Что такое Heap Dump

Heap Dump — это снимок состояния Java heap в момент времени, содержащий информацию об всех объектах в памяти и их связях. Это мощный инструмент для диагностики проблем с GC и утечками памяти.

Создание Heap Dump

Способ 1: Через jmap (при дефекте памяти)

# Найти PID процесса Java
jps -l

# Создать dump при наличии процесса
jmap -dump:live,format=b,file=heap.bin <PID>

# Пример
jmap -dump:live,format=b,file=/tmp/heap_$(date +%s).bin 12345

Способ 2: Автоматически при OutOfMemoryError

java -XX:+HeapDumpOnOutOfMemoryError \n  -XX:HeapDumpPath=/var/dumps/heapdump.bin \n  -jar myapp.jar

Способ 3: Через JVisualVM (GUI инструмент)

Запустить: jvisualvm
1. Подключиться к приложению
2. Memory вкладка
3. Нажать "Heap Dump"
4. Сохранить файл

Способ 4: Через jcmd

jcmd <PID> GC.heap_dump /tmp/heapdump.bin

Анализ Heap Dump

Инструменты анализа:

  • Eclipse MAT (Memory Analyzer Tool) — мощный профессиональный инструмент
  • JProfiler — GUI анализ
  • YourKit — интерактивный анализ
  • Heap Hero — облачный анализ
  • JDK jhat — встроенный инструмент

Признаки проблем с GC в Heap Dump

1. Утечка памяти (Memory Leak)

// Проблемный код
public class MemoryLeakExample {
    private static List<byte[]> cache = new ArrayList<>();
    
    public void addToCache(byte[] data) {
        cache.add(data);  // Объекты никогда не удаляются!
    }
    
    public void clearCache() {
        cache.clear();
    }
}

В Heap Dump видишь:

  • Огромное количество одинаковых объектов
  • Растущий размер одной коллекции
  • Пути до них идут от static полей

Найти утечку в Eclipse MAT:

1. Открыть heap dump
2. Leak Suspects → Report
3. Увидишь объекты, держащие большую часть памяти
4. Trace Back to Garbage Collection Root
5. Найдёшь цепочку ссылок до статических полей

2. Чрезмерное создание объектов (Object Proliferation)

// Неэффективный код
public String processString(String input) {
    String result = input;
    for (int i = 0; i < 1000; i++) {
        result = result + "_" + i;  // Создаёт новый String на каждой итерации!
    }
    return result;
}

// Правильный код
public String processString(String input) {
    StringBuilder result = new StringBuilder(input);
    for (int i = 0; i < 1000; i++) {
        result.append("_").append(i);
    }
    return result.toString();
}

В Heap Dump видишь:

  • Множество экземпляров одного класса (например, String)
  • Размер объектов небольшой, но их очень много
  • В список попадает java.lang.String на 50-70% памяти

3. Неправильная работа GC (Heap Fragmentation)

Видишь в Heap Dump:
- Много объектов возраста 0 (молодое поколение переполнено)
- Old generation заполнено на 90%+
- Множество больших объектов, которые не удаляются

Решение:

# Увеличить размер heap
java -Xmx4g -jar myapp.jar

# Оптимизировать GC
java -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar myapp.jar

Практический анализ в Eclipse MAT

Шаг 1: Открыть Heap Dump

File → Open Heap Dump → выбрать heap.bin

Шаг 2: Посмотреть Dominator Tree

Window → Heap Dump Analysis → Dominator Tree

Это показывает объекты, занимающие больше всего памяти
и какие ссылки их держат в памяти

Шаг 3: Анализировать путь до GC Root

// Если видишь в Dominator Tree большой List<User>
User[] → List → HashMap → CacheManager (static) → Class

// Это значит:
public class CacheManager {
    private static HashMap<String, List<User>> cache = new HashMap<>();
    // static поле держит ссылку, объекты никогда не удаляются
}

Шаг 4: OQL (Object Query Language) запросы

-- Найти все String длиной > 100 символов
SELECT * FROM java.lang.String s WHERE s.value.length > 100

-- Найти все HashMap, которые содержат > 1000 элементов
SELECT * FROM java.util.HashMap h WHERE h.table.length > 1000

-- Найти все объекты User
SELECT * FROM com.example.User

Детектирование проблем через GC логи

Включить GC logging:

java -XX:+PrintGCDetails \n  -XX:+PrintGCDateStamps \n  -Xloggc:/var/logs/gc.log \n  -jar myapp.jar

Анализировать логи:

2024-01-15T10:23:45.123+0000: 12.345: [GC (Allocation Failure)
  [PSYoungGen: 8388000K->1000K(9216000K)] 
  8388000K->1388000K(15728640K), 0.0234567 secs]

Что это означает:
- Young Generation: 8GB → 1MB (хорошо, объекты собрали)
- Полная heap: 8GB → 1.3GB
- Пауза GC: 23 миллисекунды (приемлемо)

Признаки проблем в GC логах:

1. Частые Full GC
   [Full GC (Ergonomics) ... 0.5234 secs]  // > 0.5 сек = плохо

2. Растущий размер heap после GC
   [PSYoungGen: 9000K->8000K]  // Почти ничего не собрали

3. GC паузы растут со временем
   0.023 → 0.045 → 0.089 сек  // Trend к замедлению

Правильная интерпретация

Утечка памяти:

  • После GC размер heap не уменьшается
  • Одно и то же выделение памяти происходит каждый цикл
  • В Dominator Tree видны огромные коллекции, которые никогда не чистятся

Неправильный размер Heap:

  • Full GC происходит слишком часто
  • Heap постоянно > 85% заполнен
  • Нужно увеличить -Xmx

Неправильный выбор GC:

  • При 32+ GB памяти используется ParallelGC (нужен G1GC)
  • Высокие паузы GC (> 100ms) — нужен GC с низкой паузой

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

  1. Регулярно снимай Heap Dumps перед выпуском
  2. Анализируй GC логи в production
  3. Мониторь память через Micrometer
  4. Используй правильные параметры JVM для твоего случая
  5. Тестируй под реальными нагрузками
@Component
public class MemoryMonitor {
    private final MeterRegistry registry;
    
    @Scheduled(fixedRate = 10000)
    public void monitorMemory() {
        MemoryMXBean memBean = ManagementFactory.getMemoryMXBean();
        long used = memBean.getHeapMemoryUsage().getUsed();
        long max = memBean.getHeapMemoryUsage().getMax();
        
        double usage = (double) used / max * 100;
        registry.gauge("jvm.heap.usage.percent", usage);
        
        if (usage > 85) {
            log.warn("Heap usage is {}%, consider increasing -Xmx", usage);
        }
    }
}
Как увидеть из Heap Dumps ошибку в работе Garbage Collection | PrepBro