1

私は次のコードを書くようになりました:

public class foo {

    static int iterationCounter = 0;

    public foo() {
        iterationCounter++;
        System.out.println(iterationCounter);
        new foo();

    }

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

    }


}

StackOverflow 例外が生成される前に、値から作成された最後のログiterationCounterは: でした。11472そのため、Java はfoo オブジェクトxを作成するためにメモリ量を確保しました。11472

ただし、次のコードは、他のプログラムとは異なるログを出力します。

public class foo {

    static int iterationCounter = 0;
    foo fooObject;

    public foo() {
        iterationCounter++;
        System.out.println(iterationCounter);
        this.fooObject = new foo();

    }

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

    }


}

ここで、メモリ管理に関して私の混乱が生じます。の値は他のプログラムと同じだと思っていたのですがiterationCounter、今回の値は9706です。はパブリック変数 (フィールド) であるためfooObject、スタック メモリではなくヒープ メモリに格納する必要があります (そうではありませんか?)。この場合、スタックのスペースを消費するべきではありませんか (または、新しく作成されたすべての fooObjects とそのすべてのプロパティをスタックに格納していますか)?

4

2 に答える 2

3

最初のバージョンでは、次のコードが生成されます (の出力javap -c ...)。

   ...                                     
   18:  invokevirtual   #4; //Method java/io/PrintStream.println:(I)V            
   21:  new     #5; //class Test                                                 
   24:  dup                                                                      
   25:  invokespecial   #6; //Method "<init>":()V                                
   28:  pop                                                                      
   29:  return          

そして2番目のもの - 以下:

   ...                                       
   18:  invokevirtual   #4; //Method java/io/PrintStream.println:(I)V                 
   21:  aload_0                                                                       
   22:  new     #5; //class Test                                                      
   25:  dup                                                                           
   26:  invokespecial   #6; //Method "<init>":()V                                     
   29:  putfield        #7; //Field test:LTest;                                       
   32:  return 

ご覧のとおり、再帰呼び出し前のこれらのリストの唯一の違いはaload_0、2 番目のリストの 21 行目です。

その操作は、ローカル変数の値0(それはthis) をスタックにロードするため、後で操作によるオブジェクト参照として使用できますputfield

thisしたがって、観察される違いは、スタックでの呼び出しごとに 1 つの余分なエントリ (フィールドに値を書き込むために使用される参照) の存在によって引き起こされます。

于 2012-09-10T14:16:19.180 に答える
0

したがって、Java は 11472 個の foo オブジェクトを作成するために x 量のメモリを確保します。

オブジェクトはヒープに割り当てられ、不足することはありません。OutOfMemoryError が発生します。

不足するのは、StackOverflowError のあるスタックです。ローカル変数がないため、スタックで使用しているのは状態を保存することだけなので、深さは比較的高くなります。

iterationCounter の値は他のプログラムと同じになると思っていたのですが、今回は 9706 です。

あなたが効果的に持っている可能性はかなり高いです

foo $local_variable$ = new foo();
this.fooObject = $local_variable$

これは、各再帰でより多くのスタックが使用されることを意味します (もう 1 つの参照)

于 2012-09-10T14:14:31.783 に答える