是否有javac和hotspot完成的优化列表?

时间:2016-05-27 18:35:17

标签: java javac jvm-hotspot

我最近一直在和同事讨论什么是好的代码。具体而言,出现了循环内分配的问题。我已经看到多个案例(在其他语言中),在一个循环中分配变量可能会有严重的惩罚,而且我一次又一次地经历和看到的智慧指出,避免这些明显危险的事情是最好的。

然而,似乎这不是widely accepted,许多人建议应该依赖热点和javac来解决任何明显的错误,比如在循环中分配,事实上鼓励这种做法。

我在Java中对此很好,因为它似乎始终为你提升变量的声明而没有任何不良影响。但我不知道鼓励其他错误是最佳做法。当有人告诉我做这样的事情时,是否有可用于验证行为的资源?

1 个答案:

答案 0 :(得分:0)

似乎存在很大的误解。比较时

String str;
while(condition){
    str = calculateStr();
    .....
}

while(condition){
    String str = calculateStr();
    .....
}

实际操作calculateStr()以及结果字符串的分配总是在循环内部发生。因此,在这两种情况下,都需要HotSpot来确定calculateStr()内的操作是否是不变的,并且可以移出循环。

相反,局部变量存在于堆栈帧中,一个在方法入口处分配的数据结构,在方法出口处释放(尽管“分配”和“释放”通常仅意味着“移动堆栈”指针“)并且足够大以容纳在方法执行期间可能同时存在的所有局部变量。

因此,在任何一种情况下,堆栈帧内都必须有一个位置来保存str的值(在字节代码级别上,本地变量由索引访问)。但有趣的是,如果你有多个局部变量,减少变量的范围可以通过在堆栈帧中重用变量的内存位置来减少所需的内存。 / p>

所以当你写:

String one;
int two;
while(condition1){
    one = calculateStr();
    .....
}
while(condition2){
    two = calculateInt();
    .....
}

您的堆栈框架中有两个变量,映射到onetwo。相反,当你写:

while(condition1){
    String one = calculateStr();
    .....
}
while(condition2){
    int two = calculateInt();
    .....
}

堆栈帧中只有一个局部变量,在第一个循环期间映射到one并在第二个循环内映射到two

也许您首先需要了解的是,本地变量的声明及其超出范围都不会产生任何成本。如上所述,每个局部变量在堆栈帧内具有其预定位置,并且堆栈帧在方法入口处被分配并且持续整个方法执行。当一个实际值被写入它时,变量就会生效,它发生在所有变体的同一个地方,当它超出范围时,什么都不会发生。当它在以后重用时,实际写入一个新值,甚至可能是不同类型的值,建立新变量,尽管从JVM的角度来看,它是相同的还是不同的变量并不重要

换句话说,局部变量的名称和范围以及在某种程度上甚至类型都只是源级工件(将调试元信息放在一边)。在字节代码级别,它们永远不会被创建或销毁,只能被写入和读取。但是限制源代码范围可以为不同的变量重用相同的位置,从而可能减少堆栈帧大小。