Java 为什么在循环中使用字段引用之前将其复制到本地?

Java 为什么在循环中使用字段引用之前将其复制到本地?,java,Java,这个OpenJDK产品线的优势是什么 代码段: private final char value[]; // ... public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; // <--- this line for (int i = 0; i < value.len

这个OpenJDK产品线的优势是什么

代码段:

private final char value[];
// ...
public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {



        char val[] = value;      // <--- this line



        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}
私有最终字符值[];
// ...
公共int hashCode(){
int h=散列;
如果(h==0&&value.length>0){

char val[]=value;//我查看了字节码,正如@user所评论的,这可能是为了避免循环中的
getfield
调用而进行的优化。但是他们弄糟了,仍然在循环条件中引用value变量……所以这实际上使字节码变长变慢了

public int h1() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;
        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

public int h2() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        for (int i = 0; i < value.length; i++) {
            h = 31 * h + value[i];
        }
        hash = h;
    }
    return h;
}
如果他们将循环条件更改为也使用本地字段

...
for (int i = 0; i < val.length; i++) {
...
在我的jdk 1.7.0_79上对该方法进行了数百万次循环的愚蠢测试,结果始终显示原始方法的运行时间是未“优化”或正确“优化”方法的5倍。后两种方法在性能上没有差异

所以我想,总之,本地存储字段是一种试图优化方法字节码的尝试,可能是在jit能够优化它之前,但是他们把它搞砸了,实际上使方法变得更糟

这段代码实际上是用Java 9修复的,

当然,我认为这是多余的,也不明白为什么。这没有好处。即使他们没有复制它。这只是有额外的参考。很好,你发现了这一点1。我认为这是Java开始时留下的。当时没有JIT编译器,通过访问(局部)变量更快-至少这是当时的一个普遍看法。不确定这是否真的是真的(但我在C程序中也看到过这种模式,因为局部变量保存在CPU寄存器中,而实例变量需要从(堆)中读取)记忆。这里有一个类似的问题,看看维维安的答案,我猜可能是和的重复。
...
for (int i = 0; i < val.length; i++) {
...
 public int h1();
Code:
   0: aload_0       
   1: getfield      #17                 // Field hash:I
   4: istore_1      
   5: iload_1       
   6: ifne          50
   9: aload_0       
  10: getfield      #15                 // Field value:[C
  13: arraylength   
  14: ifle          50
  17: aload_0       
  18: getfield      #15                 // Field value:[C
  21: astore_2      
  22: iconst_0      
  23: istore_3      
  24: goto          39
  27: bipush        31
  29: iload_1       
  30: imul          
  31: aload_2       
  32: iload_3       
  33: caload        
  34: iadd          
  35: istore_1      
  36: iinc          3, 1
  39: iload_3       
  40: aload_2       
  41: arraylength   
  42: if_icmplt     27
  45: aload_0       
  46: iload_1       
  47: putfield      #17                 // Field hash:I
  50: iload_1       
  51: ireturn