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

あなたの期待は不当ではありません。

ここでは、次の 2 つの力が働いています。

  • ヒープ上の person() のオブジェクト作成
  • 深層再帰によるコールスタックの拡大

これら 2 つのうちどちらが最初に失敗するかは誰にもわかりませんが、JVM の設定に大きく依存します。-Xmx を非常に低い値に設定すると、最初に OOMException が発生する可能性が高くなります。

于 2013-04-17T08:24:58.677 に答える
0

その理由は、Person() のデフォルト コンストラクターで発生した再帰呼び出しです。

この問題を説明するための JVM のより深いレベルの知識: Java 仮想マシンの仕様は、Java スタックの例外の 2 つの状況を規定しています。

  1. Java スタックは自動的に拡張できます。十分なメモリを適用できない場合、OOM(OutOfMemory) エラーがスローされます。
  2. Java スタックはスタック フレームで構成され、各 Java メソッドがフレームをプッシュすると、現在のスレッドのスタックの深さが jvm の許可されているよりも大きい場合、StackOverflowError がスローされます。

多分あなたを助ける:)

于 2013-04-17T08:24:10.520 に答える