Что такое OutOfMemoryError?

OutOfMemoryError в Java — это ошибка уровня Error, которая возникает, когда виртуальная машина (JVM) не может выделить память для нового объекта, потому что все доступные ресурсы исчерпаны и Garbage Collector не может освободить достаточно пространства.

📌 Где возникает OutOfMemoryError

Java-heap состоит из нескольких областей, и OutOfMemoryError может возникать в разных местах — в зависимости от причины.

Основные типы ошибок:

Вид ошибки Когда возникает
java.lang.OutOfMemoryError: Java heap space Закончилась память в куче (heap)
--- ---
java.lang.OutOfMemoryError: GC overhead limit exceeded GC слишком часто работает и почти не освобождает память
--- ---
java.lang.OutOfMemoryError: Metaspace Переполнена область метаданных классов (с Java 8+)
--- ---
java.lang.OutOfMemoryError: Direct buffer memory Используется слишком много off-heap памяти (например, через ByteBuffer)
--- ---
java.lang.OutOfMemoryError: unable to create new native thread Не удаётся создать новый поток из-за нехватки системных ресурсов
--- ---

🔍 Почему возникает OutOfMemoryError

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

Объекты, на которые сохраняются ссылки, несмотря на ненадобность, не могут быть удалены GC. Например:

  • Статические коллекции (static List)

  • Неправильно реализованные кеши

  • Незакрытые слушатели (например, в Android: LiveData.observe)

  • Вложенные классы, захватывающие контекст Activity

2. Создание слишком большого количества объектов

List&lt;int\[\]&gt; list = new ArrayList<>();
while (true) {
list.add(new int\[1_000_000\]);
}

→ Быстрое потребление кучи → OutOfMemoryError.

3. Рекурсия без выхода (стековый overflow)

Хоть это технически вызывает StackOverflowError, но при создании новых объектов в глубокой рекурсии также можно получить OutOfMemoryError.

4. Слишком много потоков

while (true) {
new Thread(() -> {}).start();
}
 OutOfMemoryError: unable to create new native thread

5. Метаданные классов (до Java 8 — PermGen, с Java 8 — Metaspace)

  • Слишком много загруженных классов (например, при создании новых ClassLoader)

  • Динамическая генерация прокси и лямбд

 OutOfMemoryError: Metaspace

🛠 Как диагностировать и решать

1. Увеличить память JVM

Пример для увеличения heap:

java -Xmx1024m MyApp

Другие флаги:

  • -Xms — начальный размер кучи

  • -Xmx — максимальный размер кучи

  • -XX:MaxMetaspaceSize=... — лимит Metaspace

2. Профилирование и поиск утечек

Используйте:

  • **VisualVM
    **
  • **YourKit
    **
  • **JProfiler
    **
  • **MAT (Memory Analyzer Tool)
    **

→ они помогут выявить объекты, которые не освобождаются.

3. Использование слабых/мягких ссылок

Если объект можно восстановить, лучше использовать WeakReference или SoftReference, чтобы не мешать GC.

4. Оптимизация кода

  • Избегать больших массивов в памяти

  • Не кэшировать всё подряд

  • Закрывать потоки, слушатели и Context-зависимые ресурсы

  • Использовать try-with-resources для автоматического освобождения

❗ OutOfMemoryError — это ошибка, а не исключение

  • Это unchecked ошибка (extends Error)

  • Не должна ловиться в обычных условиях (catch (Throwable) — допустимо, но опасно)

  • Обычно требует **пересмотра архитектуры и логики работы с памятью
    **

🧠 Кратко

OutOfMemoryError означает, что JVM не может выделить память, потому что:

  • Объекты не удаляются (утечки)

  • Память заканчивается из-за перегрузки

  • Лимиты памяти слишком малы

Решение требует анализа причин и оптимизации управления памятью в приложении.