[英]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.