Java 决赛 performance/optimization

Java final performance/optimization

所以我 运行 对不同的数据结构进行了一些基准测试,并注意到,当我将变量声明为 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
没有最终:EnumSet: 802 121 596ns

这是始终可重现的!

为什么使用 final 的代码和不使用 final 的代码之间存在如此巨大的差异?为什么没有得到优化?为什么 final 更快,生成的字节码有什么区别?

如果某些东西永远无法改变,您可以进行各种优化,例如实际值的内联,而不是一遍又一遍地查找它。这只是您可以做的一件事,它很容易解释并能带来最大的好处。

还有许多其他影响较小的更深奥的事情发生。

如果您查看字节码,您会看到这一点,尤其是在 JIT 启动之后。

制作整个 class final 可以有类似的好处。

That said, final references will not always provide measurable gains, it depends on the usage of the reference. In this case EnumSet does a lot of special sauce stuff under the hood if you look at the source. Immutable references probably get inlined as part of that.

另请注意,您看到的行为可能会在 JVM 的未来版本中消失,或者不会出现在其他 JVM 实现中。任何事情都可能发生变化,所以不要依赖任何一种特定的实施方式。

Here is some more information in greater detail about all the idiomatic uses of final.