← Назад к вопросам
Какая ошибка вылетает, когда заканчивается место в Stack?
1.8 Middle🔥 121 комментариев
#Основы Java
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Ошибка StackOverflowError в Java
Когда в Java стеке вызовов заканчивается место, вылетает исключение StackOverflowError. Это происходит обычно при бесконечной рекурсии или очень глубокой цепочке вызовов методов.
Причины возникновения
StackOverflowError возникает в следующих ситуациях:
- Бесконечная рекурсия без базового случая
- Очень глубокая рекурсия
- Циклические вызовы методов
- Превышение лимита размера стека
Пример 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
- Это значит, его нельзя поймать как обычное исключение
- Всегда нужен базовый случай при рекурсии
- Лучше использовать итерацию вместо рекурсии для больших объёмов
- Мемоизация помогает оптимизировать дорогостоящие рекурсивные вычисления