Какое исключение возникает, если заканчивается память в стеке?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
StackOverflowError в Java
StackOverflowError — это исключение, которое возникает, когда заканчивается место в стеке вызовов (call stack) JVM. Это Error, а не Exception, что означает, что его обычно нельзя обработать и приложение должно завершиться.
Природа исключения
В Java есть два типа памяти:
- Heap — для объектов (контролируется GC)
- Stack — для локальных переменных и вызовов методов (строго ограничен размер)
Каждый вызов метода создаёт новый stack frame с локальными переменными. Если вызовов накопится слишком много, стек переполнится и возникнет StackOverflowError.
Основные причины
1. Бесконечная рекурсия (самая частая)
public class RecursionExample {
public static void infiniteRecursion(int n) {
System.out.println(n);
infiniteRecursion(n + 1); // Никогда не останавливается!
}
public static void main(String[] args) {
infiniteRecursion(0); // StackOverflowError
}
}
Выход: Exception in thread "main" java.lang.StackOverflowError
2. Косвенная рекурсия
public class IndirectRecursion {
public void methodA() {
methodB();
}
public void methodB() {
methodA(); // A вызывает B, B вызывает A — бесконечно
}
}
3. Очень глубокая рекурсия (превышение лимита стека)
public class DeepRecursion {
public static long factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1); // Со временем переполнится
}
public static void main(String[] args) {
factorial(10000); // StackOverflowError
}
}
Разница: Error vs Exception
| Характеристика | Error | Exception |
|---|---|---|
| Наследует | Throwable | Throwable |
| Обработка | Не следует ловить | Должна быть обработана |
| Причина | Системные проблемы (память, стек) | Ошибки приложения |
| Пример | StackOverflowError, OutOfMemoryError | NullPointerException, IOException |
// ❌ Плохо — пытаться ловить StackOverflowError
try {
infiniteRecursion(0);
} catch (StackOverflowError e) {
System.out.println("Ошибка!"); // Не сработает, стек уже завален
}
// ✅ Правильно — предотвратить рекурсию
if (n > maxDepth) {
throw new IllegalArgumentException("Слишком глубокая рекурсия");
}
Как избежать
1. Всегда добавляй базовый случай
public static long factorial(int n) {
if (n <= 1) return 1; // ← Base case!
return n * factorial(n - 1);
}
2. Используй итерацию вместо рекурсии
// Рекурсия (рискованно для больших n)
public static int sumRecursive(int[] arr, int index) {
if (index == arr.length) return 0;
return arr[index] + sumRecursive(arr, index + 1);
}
// Итерация (безопасно)
public static int sumIterative(int[] arr) {
int sum = 0;
for (int num : arr) {
sum += num;
}
return sum;
}
3. Увеличь размер стека (если нужно)
# При запуске JVM
java -Xss4m MyApplication # 4 MB для стека вместо дефолтного 1MB
4. Используй структуры данных для замены рекурсии
// Вместо рекурсии - стек или очередь
public class TreeTraversal {
public void depthFirstSearch(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
System.out.println(node.value);
if (node.right != null) stack.push(node.right);
if (node.left != null) stack.push(node.left);
}
}
}
Отладка
Если StackOverflowError возникает в продакшене:
- Включи full stack trace:
jvm -XX:+PrintStackTraceOnException - Найди метод, который вызывает сам себя (look for repeating method names)
- Добавь условие выхода или замени рекурсию итерацией
- Увеличь
-Xssесли это авторитетный случай (например, deep tree parsing)
Итого
StackOverflowError возникает при переполнении стека вызовов, обычно из-за неконтролируемой рекурсии. Это Error, который нельзя обработать, поэтому проактивное предотвращение (базовые случаи, итерация вместо рекурсии) — ключ к надёжному коду.