簡體   English   中英

迭代構造函數內存混淆

[英]Iterative constructor memory confusion

我是來寫下面的代碼的:

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 留出x量的內存來創建11472 foo 對象。

然而,以下代碼輸出的日志與其他程序的日志不同:

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 及其所有屬性都存儲在堆棧中)?

第一個版本生成以下代碼( 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          

第二個 - 以下內容:

   ...                                       
   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 

如您所見,遞歸調用之前這些列表之間的唯一區別是第二個列表中第 21 行的aload_0

該操作將局部變量0 (它是this )的值加載到堆棧上,以便稍后可以通過putfield操作將其用作對象引用。

因此,您觀察到的差異是由於堆棧上每次調用都存在一個額外條目 - 一個用於將值寫入字段的this引用。

因此 Java 留出 x 量的內存來創建 11472 個 foo 對象。

對象在堆上分配,您不會用完它。 你會得到一個 OutOfMemoryError。

您將耗盡的是帶有 StackOverflowError 的堆棧。 由於您沒有局部變量,因此您在堆棧上使用的所有內容都是保存需要返回的狀態,因此您的深度相對較高。

我以為iterationCounter的值會和其他程序一樣,結果這次是9706

你很可能有效地擁有

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

這意味着每次遞歸都會使用更多的堆棧(多一個參考)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM