Какие операции могут (не) генерировать StackOverflowError? - PullRequest
4 голосов
/ 13 февраля 2012

Когда будет брошено StackOverError?

Вернее, когда он будет не брошен?

Например, , например , если мы используем примитивные операторы +, +=, -, -=, == <, >, /, % и т. Д .:

try {
     // operations +, +=, -, -=, == <, >, /, %, etc
} catch (java.lang.StackOverflowError e) {
     // will never occur?
}

Есть ли гарантия, что StackOverflowError не будет брошено?

Ответы [ 5 ]

4 голосов
/ 13 февраля 2012

Теоретически, на некотором странном JVM + оператор может быть реализован с использованием внутренней рекурсии, добавив + 1 в рекурсивный цикл. Другие операторы также могут быть реализованы с использованием внутреннего вызова метода.

Я не думаю, что это когда-нибудь случится. В каждой типичной JVM / архитектуре эти операции реализуются с использованием одной операции / инструкции. Для всех этих операторов есть инструкции байт-кода, и я ожидаю, что они переведены 1: 1 в сборку. Но в JLS нет никаких гарантий.

Кстати, JavaDoc:

Брошенный, когда переполнение стека происходит, потому что приложение возвращается слишком глубоко.

не совсем правильно. Вы можете получить StackOverflowError без какой-либо рекурсии - если у вас очень глубокое дерево вызовов и у методов очень длинный список аргументов. Однако на практике это очень трудно достичь.

4 голосов
/ 13 февраля 2012

Единственная ссылка на StackOverflowError в спецификации языка Java: следующие :

15.12.4.5 Создание кадра, синхронизация, управление передачей

Метод m в некотором классе S был идентифицирован как вызываемый.

Теперь создается новый кадр активации, содержащий целевую ссылку (если есть) изначения аргумента (если есть), а также достаточно места для локальных переменных и стека для вызова метода, а также любая другая бухгалтерская информация, которая может потребоваться реализацией [...]. Если для создания такого кадра активации недостаточно памяти, выдается StackOverflowError.

В спецификации JVM указано следующее:

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

Итак, судя по приведенным выше утверждениям ...

Мне было интересно, правда ли, что код, который не вызывает никаких функций, никогда не будет генерировать Java.lang.StackOverflowError?

... да, это правда.

Например, если я использую операторы +, +=, -, -=, ==, <, >, /, % и т. Д. На примитивах (включая long и double),

Правильно.Никто из них никогда не вызовет (сам по себе) метод и поэтому не должен вызывать StackOverflowError.

2 голосов
/ 13 февраля 2012

Например, если я использую операторы +, +=, -, -=, == <, >, /, % и т. Д.примитивы (включая long и double) ... Можем ли мы гарантировать, что из-за этой операции не возникнет ошибка переполнения стека?

Да, для стандартных операторов математики и сравнения.Ключ был там, где вы сказали "... о примитивах ..." Поскольку Java не допускает перегрузку операторов, и реализация их JVM для примитивов не будет включать рекурсию, вы можете быть уверены.Это не обязательно будет иметь место, если вы говорите о не-примитивах, когда некоторые из этих операторов могут вызвать вызов не-JVM-кода (например, с помощью + для добавления объекта в строку, что вызоветметод toString объекта).

2 голосов
/ 13 февраля 2012

См. Документацию:

Брошенный, когда переполнение стека происходит, потому что приложение слишком глубоко повторяется.

Так, когда ваше приложение вообще не рекурсивно (т.е.не вызывает методы), вы не получите StackOverflowError.

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

Пример:

int foo = 23;

foo = 23 + bar;

Что, если bar является java.lang.Integer?Java автоматически сделает распаковку , и это приведет к следующему байт-коду:

   0:   bipush  23
   2:   istore_1
   3:   bipush  23
   5:   getstatic   #3; //Field bar:Ljava/lang/Integer;
        v v v v v v v 
   8:   invokevirtual   #4; //Method java/lang/Integer.intValue:()I
        ^ ^ ^ ^ ^ ^ ^
   11:  iadd
   12:  istore_1
   13:  return

Это (неявный) вызов метода и, следовательно, может вызвать StackOverflow.

0 голосов
/ 14 февраля 2012

это правда, что код, который не вызывает никаких функций, никогда не будет выдавать java.lang.StackOverflowError?

A StackOverflowError is-a VirtualMachineError.Оказывается, существует нет гарантий без бросков около VirtualMachineError s .Спецификация виртуальной машины Java гласит следующее (выделение добавлено).

Эта спецификация не может предсказать, где могут возникнуть внутренние ошибки или ограничения ресурсов, и не предписывает точно, когда о них можно сообщить.Таким образом, любой из подклассов VirtualMachineError, определенных ниже, может быть выдан в любое время во время работы виртуальной машины Java: ... StackOverflowError

...