Какие операции могут (не) выбросить StackOverflowError?
Когда будет a StackOverError
быть брошенным?
Или, скорее, когда это не будет брошено?
Для примера, если мы используем примитивные операторы +
, +=
, -
, -=
, ==
<
, >
, /
, %
, etc:
try {
// operations +, +=, -, -=, == <, >, /, %, etc
} catch (java.lang.StackOverflowError e) {
// will never occur?
}
Есть ли какая-то гарантия, что StackOverflowError
не будет брошен?5 ответов:
Верно ли, что код, который не вызывает никаких функций, никогда не бросит
java.lang.StackOverflowError?
A
StackOverflowError
это-аVirtualMachineError
. Оказывается, что нетникаких гарантий отсутствия броска оVirtualMachineError
s . Спецификация виртуальной машины Java говорит следующее (курсив добавлен).Эта спецификация не может предсказать, где могут возникнуть внутренние ошибки или ограничения ресурсов. быть встречены и не предписывает точно, когда они могут быть сообщены. Таким образом, какой-нибудь из подклассов VirtualMachineError, определенных ниже, могут быть брошены в в любое время во время работы виртуальной машины Java: ...
StackOverflowError
Теоретически, на некотором странном JVM
Я не думаю, что это когда-нибудь произойдет. В каждой типичной архитектуре JVM / эти операции реализуются с использованием одной операции / инструкции. Для всех этих операторов существуют инструкции байт-кода, и я ожидаю, что они будут переведены 1:1 в сборку. Но их нет. гарантии в JLS.+
оператор может быть реализован с помощью рекурсии внутренне путем добавления+ 1
в рекурсивный цикл. Другие операторы также могут быть реализованы с помощью внутреннего вызова метода.Кстати Джавадок:
Выбрасывается, когда происходит переполнение стека, потому что приложение рекурсирует слишком глубоко.
Не совсем правильно. Вы можете получить
StackOverflowError
без рекурсии - если у вас очень глубокое дерево вызовов и методы имеют очень длинный список аргументов. Однако это очень трудно сделать на практике.
Единственной ссылкой на
StackOverflowError
в спецификации языка Java является следующая :15.12.4.5 Создать Кадр, Синхронизировать, Передать Управление
Метод
m
в некотором классеS
был определен как вызываемый.Теперь создается новый фрейм активации, содержащий целевую ссылку (если таковая имеется) и значения аргументов (если таковые имеются), а также достаточно места для локальных переменных и стека для метода. вызывается и любая другая бухгалтерская информация, которая может потребоваться при реализации [...]. Если для создания такого фрейма активации недостаточно памяти, то выбрасывается
StackOverflowError
.В спецификации JVM говорится следующее:
Итак, судя по приведенным выше утверждениям...
StackOverflowError:
реализация виртуальной машины Java исчерпала пространство стека для потока, обычно потому, что поток выполняет неограниченное число рекурсивных вызовов в результате ошибки в исполняющаяся программа.мне было интересно, правда ли, что код, который не вызывает никаких функций, никогда не бросит java.яз..StackOverflowError?
...да, это правда.
например, если я использую операторы
+
,+=
,-
,-=
,==
,<
,>
,/
,%
и т.д. на примитивах (включая длинные и двойные),Верно. Ни один из них будут ли они когда-либо (сами по себе) вызывать метод и, следовательно, не должны вызывать
StackOverflowError
.
Например, если я использую операторы
+
,+=
,-
,-=
,==
<
,>
,/
,%
и т.д. на примитивах (включаяlong
иdouble
)...Можем ли мы гарантировать, что ошибка stackoverflow не будет выброшена из этой операции?Да, для стандартных операторов математики и сравнения. Ключ был там, где вы сказали "...о первобытных людях..." так как Java не допускает перегрузки операторов, и реализация JVM их для примитивов вы можете быть уверены, что это не повлечет за собой рекурсии. Это не обязательно будет иметь место, если вы говорите о непримитивах, где некоторые из этих операторов могут вызвать вызов кода, не являющегося JVM (например, с помощью
+
для добавления объекта к строке, что вызовет метод объектаtoString
).
Смотрите документацию:
Таким образом, если ваше приложение вообще не рекурсирует (т. е. не вызывает методы), вы не получитеВыбрасывается, когда происходит переполнение стека, потому что приложение рекурсирует слишком глубоко.
StackOverflowError
. Конечно, когда мы говорим не только о примитивах (где основные операции реализуются непосредственно с помощью инструкций Java bytecode ), мы легко сталкиваемся сStackOverflowError
s.Пример:
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.