它必须是StackoverflowError或OOME

时间:2013-04-17 08:09:14

标签: java

当我在程序下面运行时

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 个答案:

答案 0 :(得分:4)

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

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

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

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

Person对象本身是在堆上创建的,但通常堆大于堆栈(至少在默认情况下是这样),因此堆栈早于堆填充。

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

java -Xss128M -Xmx4M Person

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

答案 1 :(得分:2)

您的期望并非毫无根据。

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

  • 在堆上创建person()的对象
  • 通过深度递归进行的callstack扩展

这两个中的哪一个首先失败是任何猜测,并且高度依赖于JVM的设置。将-Xmx设置为一个非常低的值,你很可能首先得到一个OOMException。

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:0)

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

在更深层次的JVM知识中解释这个问题:java虚拟机规范已经排除了java堆栈的两种异常情况:

  1. 允许Java堆栈自动扩展,它会抛出 OOM(OutOfMemory)错误,因为它无法申请足够的内存。
  2. Java堆栈由堆栈帧和每个java方法构成 推送一个帧,它会在堆栈时抛出StackOverflowError 当前线程的深度大于允许的jvm。
  3. 也许可以帮到你:)。