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)
编辑:没有价值;
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,特别是内存模型规则,允许编译器执行优化,这可能导致不同的线程看到应用程序状态的不一致版本...如果它们不同步从开发人员的角度来看,导致行为是不正确的.但真正的问题在于应用程序,而不是编译器.)
顺便说一句,一个更令人信服的理由是你不应该更改循环体中的循环变量,这会让你的代码更难理解.