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

Какая ошибка вылетает, когда заканчивается место в Stack?

1.8 Middle🔥 121 комментариев
#Основы Java

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

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

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

Ошибка StackOverflowError в Java

Когда в Java стеке вызовов заканчивается место, вылетает исключение StackOverflowError. Это происходит обычно при бесконечной рекурсии или очень глубокой цепочке вызовов методов.

Причины возникновения

StackOverflowError возникает в следующих ситуациях:

  1. Бесконечная рекурсия без базового случая
  2. Очень глубокая рекурсия
  3. Циклические вызовы методов
  4. Превышение лимита размера стека

Пример 1: Простая бесконечная рекурсия

public class StackOverflowExample {
    
    // Бесконечная рекурсия — нет базового случая
    public static void recursiveMethod() {
        recursiveMethod();  // Вызывает сам себя без условия остановки
    }
    
    public static void main(String[] args) {
        recursiveMethod();  // StackOverflowError!
    }
}

Вывод:

Exception in thread "main" java.lang.StackOverflowError
    at StackOverflowExample.recursiveMethod(StackOverflowExample.java:3)
    at StackOverflowExample.recursiveMethod(StackOverflowExample.java:3)
    ... (повторяется тысячи раз)

Пример 2: Забыли базовый случай в рекурсии

public class Factorial {
    
    // Неправильно: нет базового случая
    public static int factorial(int n) {
        return n * factorial(n - 1);  // Бесконечный спуск
    }
    
    // Правильно: есть базовый случай
    public static int correctFactorial(int n) {
        if (n <= 1) {
            return 1;  // Базовый случай — условие остановки
        }
        return n * correctFactorial(n - 1);
    }
    
    public static void main(String[] args) {
        // factorial(5);  // StackOverflowError!
        System.out.println(correctFactorial(5));  // Работает: 120
    }
}

Пример 3: Очень глубокая рекурсия

public class DeepRecursion {
    
    public static int fibonacci(int n) {
        if (n <= 1) {
            return n;
        }
        // Экспоненциальная сложность O(2^n)
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
    
    public static void main(String[] args) {
        // fibonacci(50);  // StackOverflowError! (очень глубокие вложенные вызовы)
        System.out.println(fibonacci(30));  // Работает, но медленно
    }
}

Пример 4: Циклические вызовы

public class CircularCalls {
    
    public static void methodA() {
        methodB();
    }
    
    public static void methodB() {
        methodC();
    }
    
    public static void methodC() {
        methodA();  // Вызывает методA, создавая цикл
    }
    
    public static void main(String[] args) {
        methodA();  // StackOverflowError!
    }
}

Как исправить StackOverflowError

Решение 1: Добавить базовый случай

public static long factorial(int n) {
    // Базовый случай
    if (n == 0 || n == 1) {
        return 1;
    }
    // Рекурсивный случай
    return n * factorial(n - 1);
}

Решение 2: Использовать итерацию вместо рекурсии

// Рекурсивно (опасно при больших n)
public static long factorialRecursive(int n) {
    if (n <= 1) return 1;
    return n * factorialRecursive(n - 1);
}

// Итеративно (безопасно)
public static long factorialIterative(int n) {
    long result = 1;
    for (int i = 2; i <= n; i++) {
        result *= i;
    }
    return result;
}

Решение 3: Мемоизация (кэширование результатов)

import java.util.HashMap;
import java.util.Map;

public class FibonacciOptimized {
    private static Map<Integer, Long> memo = new HashMap<>();
    
    public static long fibonacci(int n) {
        if (n <= 1) return n;
        
        // Проверяем кэш
        if (memo.containsKey(n)) {
            return memo.get(n);
        }
        
        // Вычисляем и кэшируем
        long result = fibonacci(n - 1) + fibonacci(n - 2);
        memo.put(n, result);
        return result;
    }
}

Мониторинг Stack Size

public class StackMonitor {
    
    public static void checkStackMemory() {
        ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
        ThreadInfo threadInfo = threadBean.getThreadInfo(Thread.currentThread().getId());
        System.out.println("Stack depth: " + getStackDepth());
    }
    
    private static int getStackDepth() {
        return Thread.currentThread().getStackTrace().length;
    }
    
    public static void main(String[] args) {
        System.out.println("Default stack size: " + getStackDepth());
    }
}

Увеличение размера Stack (JVM параметры)

Если нужна глубокая рекурсия, можешь увеличить размер стека при запуске JVM:

# Увеличить стек до 16 МБ (по умолчанию 1-2 МБ)
java -Xss16m MyApplication

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

Throwable
├── Exception
│   └── RuntimeException
└── Error
    ├── StackOverflowError  ← Отсюда происходит StackOverflowError
    ├── OutOfMemoryError
    └── ...

Важные моменты

  • StackOverflowError наследуется от Error, а не Exception
  • Это значит, его нельзя поймать как обычное исключение
  • Всегда нужен базовый случай при рекурсии
  • Лучше использовать итерацию вместо рекурсии для больших объёмов
  • Мемоизация помогает оптимизировать дорогостоящие рекурсивные вычисления
Какая ошибка вылетает, когда заканчивается место в Stack? | PrepBro