让我们看这个例子:
String var;
while (...) {
var = ...
// do stuff
}
在这种情况下,我们创建对String
对象的引用,并在循环的每次迭代中为其分配不同的对象。
现在,在另一个示例中:
while (...) {
String var = ...
// do stuff
}
如果我们假设编译器是幼稚的,它只会在堆栈每次迭代上分配对String
对象的引用。
或者会吗?这是我的问题-Java编译器是否执行此优化?我总是在尽可能大的范围内保留对象声明,因为我对此很担心,但是如果编译器已经这样做了,那么我的工作就少了一点。
谢谢你!
它将在每次迭代中为堆栈上的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
将在插槽2中,在第一个循环的body
另一个j
将在插槽1中,持续第二个循环。
[k
将在插槽2中,在第二个循环的body
如您所见,插槽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