虽然这不是它的主要目的,但我一直认为在某些情况和VM实现中,final
关键字可以帮助JIT。
可能这是一个谣言,但我从未想象过将字段设置为final
会对性能产生负面影响。
直到我遇到了这样的代码:
private static final int THRESHOLD = 10_000_000;
private static int [] myArray = new int [THRESHOLD];
public static void main(String... args) {
final long begin = System.currentTimeMillis();
//Playing with myArray
int index1,index2;
for(index1 = THRESHOLD - 1; index1 > 1; index1--)
myArray[index1] = 42; //Array initial data
for(index1 = THRESHOLD - 1; index1 > 1; index1--) {
//Filling the array
for(index2 = index1 << 1; index2 < THRESHOLD; index2 += index1)
myArray[index2] += 32;
}
long result = 0;
for(index1 = THRESHOLD - 1; index1 > 1; index1-=100)
result += myArray[index1];
//Stop playing, let's see how long it took
System.out.println(result);
System.out.println((System.currentTimeMillis())-begin+"ms");
}
让我们来看一下:
private static int [] myArray = new int [THRESHOLD];
。在64位W7上,基于10次连续运行的结果,我得到了以下结果:
THRESHOLD = 10^7
,1.7.0u09客户端VM(Oracle):- 当
myArray
不是final时,在约2133毫秒内运行。 - 当
myArray
是final时,在约2287毫秒内运行。 - -server VM产生类似的数字即2131ms和2284ms。
- 当
THRESHOLD = 3x10^7
,1.7.0u09客户端VM(Oracle):- 当
myArray
不是final时,在约7647毫秒内运行。 - 当
myArray
是final时,在约8190毫秒内运行。 - -server VM产生大约7653ms和8150ms。
- 当
THRESHOLD = 3x10^7
,1.7.0u01客户端VM(Oracle):- 当
myArray
不是final时,在约8166毫秒内运行。 - 当
myArray
是final时,在约9694毫秒内运行。这超过了15%的差异! - -server VM在非final版本中产生了可以忽略的有利差异,大约为1%。
- 当
备注:我使用JDK 1.7.0u09的javac生成的字节码进行了所有测试。除了myArray
声明外,两个版本生成的字节码完全相同。
那么为什么带有静态final myArray
的版本比带有静态myArray
的版本慢?
编辑(使用Aubin版本的我的片段):
似乎带有final
关键字和不带有的版本之间的差异仅在于第一个迭代。 不知何故,在第一个迭代中,带有final
的版本始终比其没有的版本慢,然后下一次迭代具有类似的时间记录。
例如,对于THRESHOLD = 10^8
并在1.7.0u09客户端上运行,第一次计算大约需要35秒,而第二次“仅”需要30秒。