Как начать анализ периодических падений сервиса из-за OutOfMemoryError (OOME)?

Ответ

Анализ следует начать со сбора и изучения дампа памяти (heap dump), созданного в момент ошибки OOME.

План действий:

  1. Включите автоматическое создание дампа при OOME, добавив в аргументы JVM:
    -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dumps
  2. Проанализируйте дамп с помощью профилировщиков:
    • Eclipse Memory Analyzer (MAT) — мощный инструмент для поиска утечек.
    • VisualVM или JProfiler — для интерактивного анализа. В них нужно:
    • Найти объекты, занимающие наибольший объем памяти (вкладка Histogram или Biggest Objects).
    • Построить путь до GC Root для этих объектов, чтобы понять, что удерживает их в памяти.
    • Искать паттерны утечек, например, коллекции, которые бесконечно растут.
  3. Изучите логи сборки мусора (GC logs), включив их:
    -Xlog:gc*:file=gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M

    Обратите внимание на частоту и длительность сборок мусора, особенно Full GC.

Пример кода с потенциальной утечкой (статическая коллекция):

public class LeakyCache {
    private static final Map<String, byte[]> CACHE = new HashMap<>();

    public void storeData(String id, byte[] data) {
        // Данные добавляются, но никогда не удаляются -> утечка
        CACHE.put(id, data);
    }
}

Дополнительные шаги: проверка настроек памяти (-Xmx, -Xms), мониторинг метрик (через JMX/Prometheus) и анализ кода на наличие подобных паттернов.

Ответ 18+ 🔞

Давай разберём эту хрень с OOME, а то уже глаза на лоб лезут. Слушай, первым делом — надо поймать эту суку на месте преступления. Не просто «ой, память кончилась», а снять отпечатки пальцев, блядь.

Что делаем, чтобы не остаться с носом:

  1. Заставляем JVM стучать на саму себя. Прикручиваем к запуску приложения волшебные ключи, чтобы при каждом таком пиздеце она автоматически вываливала дамп памяти, как пьяный свидетель в участке:

    -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/куда/ты/хочешь/эти/дампы

    Теперь при OOME в указанной папке появится файлик .hprof — это и есть полный слепок памяти в момент аварии. Золотая жила, ёпта!

  2. Начинаем следствие с профилировщиков. Берём этот дамп и засовываем в специальные штуки:

    • Eclipse Memory Analyzer (MAT) — это, блядь, как Шерлок Холмс для утечек памяти. Самый мощный.
    • VisualVM или JProfiler — тоже ничего, для первичного осмотра сгодится.

    Внутри этих штук ищем не просто кто большой, а кто виноватый:

    • Открываем вкладку Histogram (гистограмма) или Biggest Objects. Смотрим, какие объекты занимают овердохуища места. Массивы байтов? Хэш-мапы размером с Казахстан?
    • Для главных подозреваемых строим путь до GC Root (это такая функция «кто его держит?»). Это покажет, какая сволочь (чаще всего статическое поле или живая тред-пула) не отпускает эти объекты, мешая сборщику мусора их подмести.
    • Ищем паттерны-убийцы. Бесконечно растущая коллекция — классика жанра. Как в этом примере, который я сейчас высеку:
public class LeakyCache {
    // Вот она, падла! Статическая. Живёт вечно. Всё, что в неё попало, навсегда.
    private static final Map<String, byte[]> CACHE = new HashMap<>();

    public void storeData(String id, byte[] data) {
        // Данные закидываются, а удалять их никто не собирается. Прямой путь к OOME.
        CACHE.put(id, data); // С каждым вызовом могила копается глубже.
    }
}
  1. Смотрим, как работал дворник (Garbage Collector). Включаем логирование его подвигов, чтобы понять, не захлёбывался ли он:
    -Xlog:gc*:file=gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M

    Качаем логи и ищем в них признаки беды: участившиеся Full GC, которые длятся годами, но почти не освобождают памяти. Это верный знак, что память забита жирными, привязанными объектами.

Ну и по мелочи: глянь, не поставили ли вы -Xmx на 10 мегабайт для базы данных в 100 гигов. Посмотрите метрики (JMX, Prometheus) — как память росла перед падением. И просто пройдитесь по коду, выискивая вот такие же «кэши», статические коллекции или незакрытые ресурсы. Удачи, сыщик!