Как Java обрабатывает StackOverflowError? - PullRequest
0 голосов
/ 07 июня 2018

Вот мой пример приложения

public class Main {

    private long[] exceptionLevels = new long[1000];
    private int index;

    public static void main(String... args) {
        Main main = new Main();
        try {
            main.foo(0);
        } finally {
            Arrays.stream(main.exceptionLevels)
                    .filter(x -> x != 0)
                    .forEach(System.out::println);
        }
    }

    private void foo(int level) {
        try {
            foo(level + 1);
        } catch (StackOverflowError e) {
            exceptionLevels[index++] = level;
            bar(level + 1);
        }
    }

    private void bar(int level) {
        try {
            bar(level + 1);
        } catch (StackOverflowError e) {
            exceptionLevels[index++] = -level;
        }
    }
}

Иногда, когда я запускаю приложение, я вижу результат, подобный этому

8074
8073
-8074

Что на самом деле означает, что произошло следующее

  • foo (8073) вызывает foo (8074)
  • foo (8074) вызывает foo (8075), который умирает
  • foo (8074) регистрирует себя и вызывает панель (8075), котораяdies
  • foo (8074) умирает и foo (8073) ловит его, регистрирует себя и вызывает bar (8074)
  • bar (8074) вызывает bar (8075), который умирает, поэтому bar (8074)) регистрирует себя
  • возвращаясь из всех методов, изящно завершает работу

Я понял, все в порядке.Таким образом, существует понятная схема получения

X, X-1, -X

для некоторого максимального уровня для вызовов X

Но иногда вызов Main дает такой вид вывода

6962
6961
-6963

что на самом деле

X, X-1, -(X+1)

Итак, вопрос в том, как?

PS Кроме того, когда я меняю все на статическое, программа полностью меняет свое поведение, так что даже иногда я получаю большечем 3 результата.

Редактировать: Когда я запускаю это с -Xss228k, я всегда получаю

1281
1280
-1281

, но работа с -Xss1m снова приводит меня к случайному размеру стека, а иногда и к случаюописано выше.

1 Ответ

0 голосов
/ 07 июня 2018

Запуск вашего кода может привести к нескольким другим возможным выводам.На моем ПК (Java 8, Windows) я обычно получаю пару значений, таких как:

7053
-7055

, но в редких случаях я получаю:

9667
9666
-9667

Поймать любое java.lang.Error нерекомендуется, это ненормальное состояние, из-за которого JVM не может восстановиться.

...