哪些操作可能(不)抛出StackOverflowError?

时间:2012-02-13 13:17:17

标签: java operating-system jvm virtual-machine jls

什么时候会抛出StackOverError

或者更确切地说,何时会被抛出?

对于示例,如果我们使用原始运算符++=--=== {{ 1}},<>/等:

%

是否保证try { // operations +, +=, -, -=, == <, >, /, %, etc } catch (java.lang.StackOverflowError e) { // will never occur? } 不会被抛出?

5 个答案:

答案 0 :(得分:4)

理论上,在一些奇怪的JVM +运算符可以通过在递归循环中添加+ 1在内部使用递归来实现。其他运算符也可以使用内部方法调用来实现。

我认为情况永远不会如此。在每个典型的JVM /架构中,这些操作都是使用单个操作/指令实现的。所有这些运算符都有字节码指令,我希望它们以1:1的形式转换为汇编。但是JLS没有任何保证。

顺便说一下JavaDoc:

  

当由于应用程序过于冗长而发生堆栈溢出时抛出。

不是很正确。你可以得到StackOverflowError而没有任何递归 - 如果你有非常深的调用树,并且方法有很长的参数列表。然而,实际上这很难实现。

答案 1 :(得分:4)

Java语言规范中对StackOverflowError的唯一引用是the following

  

15.12.4.5创建框架,同步,转移控制

     

某个类m中的方法S已被识别为要调用的方法。

     

现在创建一个新的激活框架,其中包含目标引用(如果有)和参数值(如果有的话),以及用于调用方法的局部变量和堆栈的足够空间以及任何其他簿记信息实施可能需要[...]。 如果没有足够的可用内存来创建此类激活框架,则会引发StackOverflowError

JVM规范说明如下:

  

StackOverflowError: Java虚拟机实现已经耗尽了线程的堆栈空间,通常是因为线程正在执行无限数量的递归调用,因为执行程序。

所以,从以上陈述判断......

  

我想知道不调用任何函数的代码永远不会抛出java.lang.StackOverflowError吗?

......是的,那是真的。

  

例如,如果我使用运算符++=--===<,关于基元的>/%等(包括长和双),

右。这些都不会(自己)调用一个方法,因此不应该导致StackOverflowError

答案 2 :(得分:2)

参见文档:

  

当由于应用程序过于冗长而发生堆栈溢出时抛出。

因此,当您的应用程序根本没有递归时(即不调用方法),您将无法获得StackOverflowError

当然,当我们不讨论原始性时(基本操作直接使用Java字节码instructions实现),我们很容易遇到StackOverflowError s。

样品:

int foo = 23;

foo = 23 + bar;

如果barjava.lang.Integer怎么办? Java将执行自动unboxing,这将导致以下字节码:

   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。

答案 3 :(得分:2)

  

例如,如果我使用运算符++=--=== <,{{1}原语(包括>/)上的},%long等...我们能否保证不会从该操作中抛出stackoverflow错误?

是的,对于标准的数学和比较运算符。关键在于你说“... on primitives ...”由于Java不允许运算符重载,而JVM对原语的实现不会涉及递归,你可以肯定。如果你在讨论非基元,那么情况就不一定如此,其中某些运算符可能会导致对非JVM代码的调用(例如,使用double将对象附加到字符串,这将是触发对象的+方法。)

答案 4 :(得分:0)

  是的,不调用任何函数的代码永远不会抛出java.lang.StackOverflowError?

StackOverflowError 是-a VirtualMachineError。它发现there are no no-throw guarantees about VirtualMachineErrors。 Java虚拟机规范说明如下(强调添加)。

  

此规范无法预测内部错误或资源限制可能的位置   遇到并且没有准确地说明何时可以报告。从而,   下面定义的任何VirtualMachineError子类都可能被抛出 at   任何时候在Java虚拟机的操作期间:   ...   StackOverflowError