Неожиданное поведение StackOverflowError

1

Я знаю, что StackOverflowError бросается, когда рекурсия идет слишком глубоко (около 25000 рекурсий), но после тестирования я обнаружил, что точное количество рекурсий до того, как оно было выбрано (максимальный размер стека), изменяется между программами. Кроме того, если я запускаю бесконечно рекурсивный метод, скажем, 10 раз, то SOE бросается после рекурсий в первый раз, а b рекурсирует следующие девять раз (т.е. Другое количество рекурсий в первый раз). Кроме того, как a, так и b отличаются между запуском моего теста несколько раз.

Вот мой класс:

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class Demo {
    public static void main(String[] args) {
        List<Integer> sizes = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            int size = doTest();
            System.out.println("Test " + i + " Yielded result " + size);
            sizes.add(size);
        }
        System.out.println("Average: " + average(sizes));
    }

    private static double average(Collection<Integer> ints) {
        int sum = 0;
        for (int i : ints) {
            sum += i;
        }
        return sum / (double) ints.size();
    }

    private static int executions = 0;

    private static int doTest() {
        try {
            recurse();
        } catch (StackOverflowError e) {
            int exec = executions;
            executions = 0;
            return exec;
        }
        throw new Error("Unexpected behaviour: StackOverflowError not thrown!"); // just to keep the compiler happy
    }

    @SuppressWarnings("InfiniteRecursion")
    private static void recurse() {
        executions++;
        recurse();
    }
}

Мой вывод выглядит следующим образом:

Test 1 Yielded result 23004
Test 2 Yielded result 25060
Test 3 Yielded result 25060
Test 4 Yielded result 25060
Test 5 Yielded result 25060
Test 6 Yielded result 25060
Test 7 Yielded result 25060
Test 8 Yielded result 25060
Test 9 Yielded result 25060
Test 10 Yielded result 25060
Average: 24854.4

Но если я снова запустил свою программу, она выглядит так:

Test 1 Yielded result 23279
Test 2 Yielded result 25074
Test 3 Yielded result 25074
Test 4 Yielded result 25074
Test 5 Yielded result 25074
Test 6 Yielded result 25074
Test 7 Yielded result 25074
Test 8 Yielded result 25074
Test 9 Yielded result 25074
Test 10 Yielded result 25074
Average: 24894.5

Может ли кто-нибудь сказать мне, почему эти различия происходят между программами и при первом тесте?

Версия Java: 8 обновление 5

  • 1
    Там нет строки, говорящей "это много рекурсий, и все готово". Это зависит от того, что именно происходит в методе и что уже размещено в стеке.
  • 1
    Программы получают нормальное количество стекового пространства. Каждая функция, которая вводится в данный момент, использует некоторую ее часть (хотя я не уверен, как именно Java это обрабатывает). Количество стекового пространства, которое вы получаете, может меняться в зависимости от любого количества факторов, например, сколько оперативной памяти доступно системе при запуске вашей программы, какую ОС вы используете, будь то вторник ...
Теги:
recursion
stack-overflow

1 ответ

4
Лучший ответ

Глубина рекурсии зависит от размера вашего стека и от того, как быстро вы его используете. Точный размер стека не всегда одинаковый (именно поэтому я не знаю), но вы должны избегать приближения к этому пределу, поскольку по умолчанию другая машина будет совсем другой.

  • 0
    Это объясняет разницу между многократным запуском этой программы, но почему она отличается в первом тесте от остальных?
  • 3
    @ bcsb1001 Попробуйте добавить -XX:+PrintCompilation Я подозреваю, что ваш код компилируется, поэтому после первого использования он использует немного меньше памяти.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню