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

Относится ли OutOfMemoryError проверяемым исключением

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

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

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

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

Относится ли OutOfMemoryError к проверяемым исключениям

Прямой ответ: НЕТ. OutOfMemoryError — это непроверяемое исключение (unchecked exception). Но давайте разберемся глубже, почему это так и как это связано с архитектурой Java.

Иерархия исключений в Java

// Вся иерархия наследуется от Throwable
Throwable
├── Exception (проверяемые исключения)
│   ├── IOException
│   ├── SQLException
│   ├── ParseException
│   └── ...
├── RuntimeException (непроверяемые исключения)
│   ├── NullPointerException
│   ├── IndexOutOfBoundsException
│   ├── IllegalArgumentException
│   └── ...
└── Error (не обрабатываем!)
    ├── OutOfMemoryError         <-- Вот здесь!
    ├── StackOverflowError
    ├── InternalError
    └── ...

Важное правило:

  • Проверяемые исключения наследуются от Exception
  • Непроверяемые исключения наследуются от RuntimeException
  • Errors — это отдельная ветка, к ним не применима классификация "проверяемое/непроверяемое"

OutOfMemoryError — это Error, а не Exception

public class OutOfMemoryError extends VirtualMachineError {
    // OutOfMemoryError наследуется от VirtualMachineError
    // VirtualMachineError наследуется от Error
    // Error наследуется от Throwable
}

public abstract class VirtualMachineError extends Error {
    // Это Error, не Exception!
}

Поскольку OutOfMemoryError наследуется от Error (через VirtualMachineError), он не является ни проверяемым, ни непроверяемым исключением. Это ошибка виртуальной машины.

Почему это Error, а не Exception

Philosophical Reason:

Exceptions — это ошибки в вашей программе, которые вы можете (и должны) обработать:

  • Неверный ввод пользователя → IOException
  • Неверный SQL запрос → SQLException
  • Неверный формат данных → ParseException

Errors — это критические проблемы с Java Virtual Machine, которые вы НЕ МОЖЕТЕ обработать:

  • Кончилась память (OutOfMemoryError) — что вы сделаете?
  • Stack overflow (StackOverflowError) — что вы сделаете?
  • Внутренняя ошибка JVM (InternalError) — что вы сделаете?

Это признак критического отказа системы, а не обработка исключительной ситуации.

Примеры OutOfMemoryError

// Пример 1: Heap exhaustion
public class OutOfMemoryDemo {
    public static void main(String[] args) {
        List<byte[]> list = new ArrayList<>();
        
        while (true) {
            // Каждый раз выделяем 1MB памяти
            byte[] array = new byte[1024 * 1024];
            list.add(array);
            
            // Рано или поздно произойдет:
            // java.lang.OutOfMemoryError: Java heap space
        }
    }
}

// Пример 2: Бесконечная рекурсия
public class StackOverflowDemo {
    public static void recursion() {
        recursion();
    }
    
    public static void main(String[] args) {
        // StackOverflowError — тоже Error!
        recursion();
    }
}

Можно ли ловить OutOfMemoryError

Технически можно, но НЕ НАДО:

// ❌ Плохо!
try {
    List<byte[]> list = new ArrayList<>();
    while (true) {
        list.add(new byte[1024 * 1024]);
    }
} catch (OutOfMemoryError e) {
    System.out.println("Памяти мало, но я всё равно продолжаю!");
}

Почему это плохо:

  1. Когда памяти кончилось, вы не можете ничего сделать
  2. Даже обработка исключения требует памяти
  3. JVM находится в нестабильном состоянии
  4. Лучше просто завершить программу

Что произойдет при попытке обработать:

try {
    // OutOfMemoryError при создании объекта
    byte[] bigArray = new byte[Integer.MAX_VALUE];
} catch (OutOfMemoryError e) {
    // Попытка логировать ошибку?
    System.err.println("OOM!")  // Может произойти ещё один OOM!
    
    // Попытка выслать алерт на сервер?
    // sendAlert();  // NetworkException? OOM при создании сокета?
    
    // Программа просто завершится с ошибкой
}

Правильный подход: Профилактика

// Вместо ловли ошибки, ПРЕДОТВРАЩАЙТЕ её:

// 1. Правильное управление памятью
public class MemoryEfficientCode {
    public List<String> processLargeFile(String filename) 
            throws IOException {
        // ❌ Плохо: загружаем весь файл в памяти
        // List<String> lines = Files.readAllLines(Paths.get(filename));
        
        // ✅ Хорошо: читаем построчно
        List<String> results = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(
                new FileReader(filename))) {
            String line;
            while ((line = reader.readLine()) != null) {
                results.add(processLine(line));
            }
        }
        return results;
    }
}

// 2. Конфигурирование JVM
// -Xmx1024m  — максимум 1GB памяти
// -XX:+HeapDumpOnOutOfMemoryError  — дамп при OOM
// -XX:HeapDumpPath=/var/logs/  — где сохранять дамп

// 3. Мониторинг памяти
public class MemoryMonitor {
    public static void main(String[] args) {
        Runtime runtime = Runtime.getRuntime();
        
        long totalMemory = runtime.totalMemory();
        long freeMemory = runtime.freeMemory();
        long usedMemory = totalMemory - freeMemory;
        
        System.out.println("Total: " + totalMemory / 1024 / 1024 + "MB");
        System.out.println("Used: " + usedMemory / 1024 / 1024 + "MB");
        System.out.println("Free: " + freeMemory / 1024 / 1024 + "MB");
        
        // Если используется 80%+ памяти, остановить обработку
        if (usedMemory > totalMemory * 0.8) {
            System.err.println("Critical memory usage!");
            System.exit(1);
        }
    }
}

Классификация

Throwable
├── Exception                    ← Проверяемые (checked)
│   └── IOException, SQLException
├── RuntimeException             ← Непроверяемые (unchecked)
│   └── NullPointerException
└── Error                        ← НЕ проверяемые и НЕ непроверяемые
    ├── OutOfMemoryError         ← ЗДЕСЬ!
    ├── StackOverflowError
    └── VirtualMachineError

Итоговый ответ

OutOfMemoryError:

  • ✅ Не проверяемое исключение (не Exception)
  • ✅ Это Error (ошибка JVM)
  • ✅ Нельзя и не нужно ловить
  • ✅ Нужно ПРЕДОТВРАЩАТЬ правильным кодом
  • ✅ Нужно мониторить и конфигурировать JVM

Классический вопрос на собеседовании, потому что показывает понимание архитектуры Java и разницы между Exception и Error.