用于优化循环语句的JVM选项

ala*_*inm 7 java optimization jvm loops

我在学校被告知,修改一个索引变量是一个不好的做法for loop:

示例:

for(int i = 0 ; i < limit ; i++){
    if(something){
        i+=2;      //bad
    }
    if(something){
        limit+=2;      //bad
    }
}
Run Code Online (Sandbox Code Playgroud)

参数是一些编译器优化可以优化循环,而不是重新计算索引并在每个循环中绑定.

我已经进行了一些测试,java似乎默认索引和绑定每次都会重新计算.

我想知道是否有可能激活这种功能JVM HotSpot

例如,优化这种循环:

for(int i = 0 ; i < foo.getLength() ; i++){   }
Run Code Online (Sandbox Code Playgroud)

无需写:

int length = foo.getLength()
for(int i = 0 ; i < length ; i++){   }
Run Code Online (Sandbox Code Playgroud)

这只是一个例子,我很想尝试看到改进.

编辑

根据Peter Lawrey的回答,为什么在这个简单的例子中JVM没有内联getLenght()方法?:

public static void main(String[] args) {
   Too t = new Too();
   for(int j=0; j<t.getLength();j++){
   }
}


class Too {

    int l = 10;
    public Too() {
    }
    public int getLength(){
        //System.out.println("test");
        return l;
    }
}
Run Code Online (Sandbox Code Playgroud)

在输出"测试"中打印10次.

我认为优化这种执行可能会很好.

编辑2: 似乎我误解了......

我已经删除了println,实际上分析器告诉我,getLength()在这种情况下,该方法甚至不会调用一次.

Pet*_*rey 13

这取决于foo.getLength()的作用.如果它可以内联,它可以是有效的相同的东西.如果无法内联,则JVM无法确定结果是否相同.

顺便说一句,你可以写一个班轮.

for(int i = 0, length = foo.getLength(); i < length; i++){   }
Run Code Online (Sandbox Code Playgroud)

编辑:没有价值;

  • 方法和循环通常不会被优化,直到它们被调用10,000次.
  • 分析器子样本调用以减少开销.他们可能会计算每10或100或更多,所以一个简单的例子可能不会出现.


Ste*_*n C 12

我已经在java中进行了一些测试,似乎默认索引和绑定每次都会重新计算.

根据Java语言规范,这个:

for(int i = 0 ; i < foo.getLength() ; i++){   }
Run Code Online (Sandbox Code Playgroud)

表示getLength()在每次循环迭代时调用.只有Java编译器可以有效地证明它不会改变可观察行为,才允许getLength()调用移出循环.(例如,如果每次只是从同一个变量返回相同的值,那么JIT编译器很可能可以内联调用,然后推断出它可以进行提升优化.但是如果涉及得到一个长度的话.并发或同步集合,允许优化的可能性很小......因为其他线程可能会采取行动.)getLength()getLength()

这就是允许编译器做的事情.

我想知道是否可以在JVM HotSpot中激活这种功能?

简单回答是不.

您似乎建议使用编译器开关来告知/允许编译器忽略JLS规则.没有这样的开关.这样的转变将是一个不好的想法.这将导致正确/有效/工作程序中断.考虑一下:

class Test {
   int count;

   int test(String[] arg) {
       for (int i = 0; i < getLength(arg); i++) {
           // ...
       }
       return count;
   }

   int getLength(String[] arg) {
       count++;
       return arg.length;
   }
}
Run Code Online (Sandbox Code Playgroud)

如果允许编译器将getLength(arg)调用移出循环,则会改变调用方法的次数,从而更改test方法返回的值.

更改正确编写的Java程序行为的Java优化不是有效的优化.(请注意,多线程会使水变得混乱.JLS,特别是内存模型规则,允许编译器执行优化,这可能导致不同的线程看到应用程序状态的不一致版本...如果它们不同步从开发人员的角度来看,导致行为是不正确的.但真正的问题在于应用程序,而不是编译器.)


顺便说一句,一个更令人信服的理由是你不应该更改循环体中的循环变量,这会让你的代码更难理解.