Какие операции могут (не) выбросить StackOverflowError?
Когда будет a StackOverError быть брошенным?
Или, скорее, когда это не будет брошено?
Для примера, если мы используем примитивные операторы +, +=, -, -=, == <, >, /, %, etc:
try {
// operations +, +=, -, -=, == <, >, /, %, etc
} catch (java.lang.StackOverflowError e) {
// will never occur?
}
Есть ли какая-то гарантия, что StackOverflowError не будет брошен?5 ответов:
Верно ли, что код, который не вызывает никаких функций, никогда не бросит
java.lang.StackOverflowError?A
StackOverflowErrorэто-аVirtualMachineError. Оказывается, что нетникаких гарантий отсутствия броска оVirtualMachineErrors . Спецификация виртуальной машины 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 ), мы легко сталкиваемся сStackOverflowErrors.Пример:
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.