我是来写下面代码的:
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 Exception 产生之前,由值 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
是一个公共(public)变量(一个字段),它应该存储在堆内存中(不是吗?)而不是堆栈内存中。如果是这种情况,它不应该占用堆栈空间(或者将所有新创建的 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
如您所见,递归调用之前这些 list 之间的唯一区别是第二个 list 中第 21 行的 aload_0
。
该操作将局部变量0
(它是this
)的值加载到堆栈上,以便以后可以将其用作putfield
的对象引用。手术。
因此,您观察到的差异是由每次调用在堆栈上存在一个额外条目引起的 - 用于将值写入字段的 this
引用。
关于java - 迭代构造函数内存困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12353256/