第一种
public void m1(){
for (int i = 0; i < 100; i++) {
Object o = new Object();
}
}
0 iconst_0
1 istore_1
2 iload_1
3 bipush 100
5 if_icmpge 22 (+17)
8 new #2 <java/lang/Object>
11 dup
12 invokespecial #1 <java/lang/Object.<init>>
15 astore_2
16 iinc 1 by 1
19 goto 2 (-17)
22 return
第二种
public void m2(){
Object o;
for (int i = 0; i < 100; i++) {
o = new Object();
}
}
0 iconst_0
1 istore_2
2 iload_2
3 bipush 100
5 if_icmpge 22 (+17)
8 new #2 <java/lang/Object>
11 dup
12 invokespecial #1 <java/lang/Object.<init>>
15 astore_1
16 iinc 2 by 1
19 goto 2 (-17)
22 return
初步结论
从字节码指令上看,两种方式并没有什么区别,只是变量i的位置从1变成了2,因为第二种方式的变量o在局部变量表中占一个位置。
变量的作用域与生命周期
变量的声明周期取决于它的作用域
- 第一种方式的变量o的作用域为m1方法,申请一次栈内存,m1方法结束时销毁
- 第二种方式的变量o的作用域为每次循环,申请100次栈内存,每次循环结束时销毁
由此可见,两种方式占用的栈内存和堆内存一致,堆内存的gc也一致。第二种方式多出了99次申请栈内存的时间。
最终结论
- 第一种方式节约了每次分配栈内存的时间,性能上略优于第二种。
- 第二种方式的变量o更符合变量作用域最小原则。