局部变量的范围如何影响Java上的加载/存储性能?

时间:2018-08-27 04:15:48

标签: java string garbage-collection

环境:      JDK1.8      Windows 10

example1:

String msg=null;
for (int i=0;i<10;i++){
     msg="Hello";
 }

和示例2:

for(int =0;i<10;i++){
      String msg = "hello";
}

谁能告诉我这两个例子之间的区别 以及哪种代码更有效

1 个答案:

答案 0 :(得分:3)

在第一个示例中,msg在所示的最外部范围内是范围内的,而在第二个示例中,msg仅在循环体中处于范围内。在继续之前,我会提醒读者,过早的优化(尤其是此处所见的微优化)通常并不适当或没有用,因此人们应该首先争取清晰,可读和可维护的代码。

我现在继续为好奇的读者。通过使用javac编译代码 1.8.0_171并用javap -c进行反汇编,我得到以下字节码:

第一种方法:

    Code:
       0: aconst_null
       1: astore_1
       2: iconst_0
       3: istore_2
       4: iload_2
       5: bipush        10
       7: if_icmpge     19
      10: ldc           #2                  // String f
      12: astore_1
      13: iinc          2, 1
      16: goto          4
      19: return

第二种方法:

    Code:
       0: iconst_0
       1: istore_1
       2: iload_1
       3: bipush        10
       5: if_icmpge     17
       8: ldc           #2                  // String f
      10: astore_2
      11: iinc          1, 1
      14: goto          2
      17: return

如您所见,这两个编译结果在本质上非常相似。两者都具有循环结构,循环的主体由负载常数(ldc)和后跟astore_<n>的局部变量插槽组成。变量对插槽的分配有所不同(第一个将i分配给插槽2,msg分配给1,第二个相反),但这不会产生重大影响。第一个确实包含两个额外的字节码,用于在第一次迭代之前将nullmsg存储。但是,这种影响非常微小,以至于无法尝试对此进行优化。

我目前没有工具集来查看JIT优化产生的机器代码,但我强烈怀疑任何有能力的JIT编译器都会优化整个循环。