2

当我在程序下面运行时

class Person{
     Person p;
     Person(){
         System.out.println("Hi");
         p = new Person();
     }
 }

public class Main {


    public static void main(String[] args) {
        new Person();
    }
}

它会引发 StackOverFlow 错误,但我希望它是 OOME,因为我们正在创建对象,而不是使用任何本地方法/变量或引用变量

4

4 回答 4

4

您是递归的并且没有调用Person()构造函数的终止条件,该构造函数将数据放在堆栈上(至少,返回地址 - 堆栈不仅用于局部变量和参数):

Person(){
    p = new Person();   // <<== Calls the Person() constructor, which again calls the Person() constructor, which again ...
}

因此,您会收到堆栈溢出错误。

理论上,编译器可以看到这是一个尾递归并优化方法调用,但这不会发生。

对象本身是在堆上创建的Person,但通常堆比堆栈大(至少默认情况下),所以堆栈比堆更早填满。

尝试使用不同的堆栈大小和最大堆大小设置运行相同的应用程序,例如

java -Xss128M -Xmx4M Person

你会得到一个OOME而不是堆栈溢出。

于 2013-04-17T08:11:46.313 回答
2

您的期望并非没有根据。

这里有两种力量在起作用:

  • 在堆上创建 person() 的对象
  • 通过深度递归扩大调用堆栈

这两个中的哪一个首先失败是任何人的猜测,并且很大程度上取决于 JVM 的设置。将您的 -Xmx 设置为非常低的值,您很可能首先会收到 OOMException。

于 2013-04-17T08:24:58.677 回答
1

因为它进入了一个无限循环,其中 Person 构造函数再次调用构造函数。

堆栈有一个限制,当它到达时会发生错误。

http://docs.oracle.com/javase/6/docs/api/java/lang/StackOverflowError.html

于 2013-04-17T08:12:36.143 回答
0

原因是在 Person() 的默认构造函数中发生了递归调用。

在更深层次的JVM知识来解释这个问题:java虚拟机规范对java栈有两种异常情况:

  1. 允许Java栈自动扩展,当申请不到足够的内存时会抛出OOM(OutOfMemory)错误。
  2. Java栈是由栈帧构成的,每个java方法push一个帧,当当前线程的栈深度大于jvm允许的深度时,会抛出StackOverflowError。

也许对你有帮助:)

于 2013-04-17T08:24:10.520 回答