【发布时间】:2017-01-24 02:21:42
【问题描述】:
所以我在不同的数据结构上运行了一些基准测试并注意到,当我将变量声明为 final 时,我得到了 10-20% 的性能提升。
这真的让我很惊讶。我认为 final 关键字纯粹用于限制变量的变化,优化会确定某个变量是否具有恒定值。
示例如下:
import javafx.scene.input.KeyCode;
import java.util.*;
public class Main {
static /*final*/ int LOOPS = Integer.MAX_VALUE / 100;
static /*final*/ KeyCode[] keyCodes = KeyCode.values();
public static void main(String[] args) {
long startTime;
long endTime;
testEnumSet(); //warmup
startTime = System.nanoTime();
testEnumSet();
endTime = System.nanoTime();
System.out.println(" EnumSet: " + (endTime - startTime) + "ns");
}
static /*final*/ EnumSet<KeyCode> enumSet = EnumSet.noneOf(KeyCode.class);
static void testEnumSet() {
for (int i = 0; i < LOOPS; i++) {
/*final*/ KeyCode add = getRandomKeyCode();
if(!enumSet.contains(add)) enumSet.add(add);
/*final*/ KeyCode remove = getRandomKeyCode();
if(enumSet.contains(remove)) enumSet.remove(remove);
}
}
/*final*/ static Random random = new Random();
static KeyCode getRandomKeyCode() {
return keyCodes[random.nextInt(keyCodes.length)];
}
}
最后:....EnumSet: 652 266 207ns
没有final:EnumSet: 802 121 596ns
这是始终可重复的!
为什么使用 final 的代码和不使用 final 的代码之间存在如此巨大的差异?为什么不优化?以及为什么无论如何 final 更快,生成的字节码有什么区别?
【问题讨论】:
-
@JarrodRoberson 评分最高的答案是没有性能提升,但我的基准测试显示约 20% 的性能提升,所以我不认为这是重复的。
-
评分最高并不意味着总是正确,有时它只是意味着大多数人都错了。就像你的发现并不总是可重复的,
final并不总是能带来任何可衡量的收益。 -
您在代码中使用了 static 最终字段。将其转换为最终实例字段(只需在
main中创建一个实例),效果可能会消失,因为静态字段参与常量折叠。实例字段 otoh 不是常量(从实例更改为实例),因此只能从冗余负载消除中受益,这仅依赖于非易失性而不是最终性。因此,如果您想对不可变对象进行基准测试而不仅仅是全局常量,那么您的基准测试就没有用处。 -
是的,你是对的,虽然这不是我的基准测试的目标,但这只是我在旁边发现的东西,让我想知道。
标签: java optimization jvm final jit