让我们看看这个例子:
String var;
while (...) {
var = ...
// do stuff
}
在这种情况下,我们创建对String
对象的引用,并在每次循环迭代中为其分配不同的对象。
现在,在另一个示例中:
while (...) {
String var = ...
// do stuff
}
如果我们假设编译器是幼稚的,那么它只会在堆栈每次迭代中分配对String
对象的引用。
还是会吗?这是我的问题-Java编译器是否执行此优化?我总是在尽可能大的范围内保留对象声明,因为我对此很担心,但是如果编译器已经这样做了,那么我的工作就少了一点。
提前谢谢!
答案 0 :(得分:4)
它只会在每次迭代时为堆栈上的String对象分配一个引用。
这不是它的工作方式。堆栈中的变量,即参数和局部变量,是在方法条目中分配(保留)的。
例如如果您有这样的代码:
static void foo() {
String s;
for (int i = 0; i < 5; i++) {
int j = i;
s = String.valueOf(j);
bar(s);
}
for (int j = 0; j < 5; j++) {
int k = j;
s = String.valueOf(k);
bar(s);
}
}
static void bar(String s) {
}
对于该代码,将在堆栈上分配3个插槽 1 :
s
将位于插槽0中,并将慢速模式用于整个方法
i
在第一个循环的持续时间内将位于插槽1中。
j
将在第一个循环的 body 持续时间内位于插槽2中。
另一个j
将在第二个循环的持续时间内位于插槽1中。
k
将在第二个循环的 body 持续时间内位于插槽2中。
如您所见,插槽1和2被重用,但是在方法执行期间没有“分配”。方法开始时只分配/撤消了内存。
1)插槽为4字节/ 32位,即int
或引用(带有压缩的Oop)的大小。
如果使用javac -g Test.java
进行编译并使用javap -v -c Test.class
进行反汇编,则会得到(Java 8的输出):
static void foo();
descriptor: ()V
flags: ACC_STATIC
Code:
stack=2, locals=3, args_size=0
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 24
7: iload_1
8: istore_2
9: iload_2
10: invokestatic #2 // Method java/lang/String.valueOf:(I)Ljava/lang/String;
13: astore_0
14: aload_0
15: invokestatic #3 // Method bar:(Ljava/lang/String;)V
18: iinc 1, 1
21: goto 2
24: iconst_0
25: istore_1
26: iload_1
27: iconst_5
28: if_icmpge 48
31: iload_1
32: istore_2
33: iload_2
34: invokestatic #2 // Method java/lang/String.valueOf:(I)Ljava/lang/String;
37: astore_0
38: aload_0
39: invokestatic #3 // Method bar:(Ljava/lang/String;)V
42: iinc 1, 1
45: goto 26
48: return
LocalVariableTable:
Start Length Slot Name Signature
9 9 2 j I
14 10 0 s Ljava/lang/String;
2 22 1 i I
33 9 2 k I
38 10 0 s Ljava/lang/String;
26 22 1 j I
如您所见,行stack=2, locals=3, args_size=0
显示它将为局部变量保留3个插槽。底部的LocalVariableTable
显示哪个局部变量在哪个字节码指令(作用域)的持续时间内使用哪个插槽。
在循环中移动s
的声明将重新排列将变量分配给插槽的顺序,即它们使用的插槽,并更改s
范围的长度,仅此而已
static void foo() {
for (int i = 0; i < 5; i++) {
int j = i;
String s = String.valueOf(j);
bar(s);
}
for (int j = 0; j < 5; j++) {
int k = j;
String s = String.valueOf(k);
bar(s);
}
}
LocalVariableTable:
Start Length Slot Name Signature
9 9 1 j I
14 4 2 s Ljava/lang/String;
2 22 0 i I
33 9 1 k I
38 4 2 s Ljava/lang/String;
26 22 0 j I