Каков план диагностики и устранения ошибки OutOfMemoryError в Java?

«Каков план диагностики и устранения ошибки OutOfMemoryError в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

1. Сбор данных (не перезапускать приложение сразу!):

  • Автоматический дамп кучи: Запускайте JVM с флагами для автоматического снятия дампа при ошибке.
    java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dump.hprof -Xmx1g -jar app.jar
  • Ручной дамп: Если приложение еще живо, снимите дамп утилитой jmap.
    jmap -dump:live,format=b,file=heap.hprof <pid>

2. Анализ дампа с помощью профилировщика:

  • Eclipse MAT (Memory Analyzer Tool) или VisualVM для анализа «тяжелых» объектов и цепочек ссылок, удерживающих память.
  • Ищите: свои классы, занимающие большую часть памяти; массивы-гиганты; коллекции без ограничения размера.

3. Поиск типичных причин:

  • Утечка памяти: Объекты, на которые остаются ссылки, но не используются (часто в статических полях, кешах, слушателях событий).
  • Чрезмерное использование памяти: Легитимные структуры данных, размер которых не контролируется (например, загрузка всего файла в память).
  • Метаданные классов (Metaspace): OutOfMemoryError: Metaspace — слишком много классов загружено (часто в серверах приложений, из-за утечки ClassLoader).

4. Решения и профилактика:

  • Исправьте утечку: Уберите ненужные ссылки, используйте WeakReference/SoftReference для кешей.
  • Настройте JVM: Увеличьте -Xmx (куча), -XX:MaxMetaspaceSize (метаданные).
  • Используйте правильные структуры данных: Например, ArrayList вместо LinkedList для хранения примитивов, если важен объем памяти.
  • Мониторинг: Настройте мониторинг потребления памяти (JMX, Prometheus) и GC-логи (-Xlog:gc*).