HashMap性能Java 9比Java 8低25%?

时间:2017-10-28 10:23:21

标签: performance-testing java-9 jmh

  

注意:这是关于性能问题的。我只观察到无法解释/理解的表现差异。

在对一些针对Java 9的新开发的代码进行基准测试时,我发现了一些奇怪的东西。带有5个密钥的HashMap的(非常)简单基准测试表明,Java 9比Java 8慢得多。这可以解释一下,还是我的(基准)代码完全错误?

代码:

@Fork(
    jvmArgsAppend = {"-Xmx512M", "-disablesystemassertions"}
)
public class JsonBenchmark {

    @State(Scope.Thread)
    public static class Data {

        final static Locale RUSSIAN = new Locale("ru");
        final static Locale DUTCH = new Locale("nl");

        final Map<Locale, String> hashmap = new HashMap<>();

        public Data() {
            hashmap.put(Locale.ENGLISH, "Flat flashing adjustable for flat angled roof with swivel");
            hashmap.put(Locale.FRENCH, "Solin pour toit plat inclinée");
            hashmap.put(Locale.GERMAN, "Flachdachkragen Flach Schrägdach");
            hashmap.put(DUTCH, "Plakplaat vlak/hellend dak inclusief glijschaal");
            hashmap.put(RUSSIAN, "Проход через плоскую кровлю регулир. для накл. кровли");
        }

    }

    @Benchmark
    public int bmHashMap(JsonBenchmark.Data data) {
        final Map<Locale, String> m = data.hashmap;
        int sum = 0;
        sum += m.get(Data.RUSSIAN).length();
        sum += m.get(Locale.FRENCH).length();
        sum += m.get(Data.DUTCH).length();
        sum += m.get(Locale.ENGLISH).length();
        sum += m.get(Locale.GERMAN).length();
        return sum;
    }    

}

结果:

  • Java 8_151:JsonBenchmark.bmHashMap thrpt 40 47948546.439±560763.711 ops / s
  • Java 9_181:JsonBenchmark.bmHashMap thrpt 40 34962904.479±276045.691 ops / s( - / - 27%!)

更新

感谢您的回答和好评。

  1. @Holger的建议。我的第一反应是:那一定是解释。但是,如果我只对String#length()函数进行基准测试,则性能没有显着差异。而且,当我只对HashMap#get()方法进行基准测试时(如@Eugene所建议的那样)仍有大约10 - 12%的差异。

  2. @Eugene的建议。我改变了参数(更多的热身迭代,更多的内存),但我无法重现你的结果。然而,我将堆增加到了4G。但这不能解释差异,不是吗?

  3. @Alan Bateman的建议。是的,这提高了性能!但是,差异仍在20%左右。

2 个答案:

答案 0 :(得分:9)

您正在测试的不只是HashMap。您不仅要致电HashMap.get,还隐式调用Locale.hashCodeLocale.equals。此外,您正在呼叫String.length

现在,所有四个都可能改变了它们的性能特征,因此您需要更多的测试来推断哪些方法表现出不同的性能。

但最热门的候选人是String.length。在Java 9中,String类不再使用char[]数组,而是使用byte[]数组,仅使用每个字符一个字节对Latin 1字符串进行编码,从而大大减少了内存占用典型应用。然而,这意味着长度不再总是与阵列长度相同。因此,此操作的复杂性已发生变化。

但请记住,您的结果是微基准测试中<77>的差异 。这还不足以估计对实际应用的影响......

答案 1 :(得分:5)

我有一个关于jmh设置的提示,而不仅仅是HashMap。正如已经提到的,你在这里测量很多而不仅仅是HashMap::get。但即便如此,我还是怀疑java-9会慢得多,所以我自己测量了(最新的jmh构建源自java-8和9)。

我还没有改变你的代码 - 只是添加了更多的堆(10GB)和更多的热身,从而减少了#34;错误&#34;你看到±

之后

使用java-8:

Benchmark            Mode  Cnt   Score   Error  Units
SOExample.bmHashMap  avgt   25  22.059 ± 0.276  ns/op

使用java-9:

Benchmark            Mode  Cnt   Score   Error  Units
SOExample.bmHashMap  avgt   25  23.954 ± 0.383  ns/op

结果几乎没有明显差异(毕竟这些都是纳秒),如你所见。此外,如果真的想要仅仅测试HashMap::get,那么你的方法就可以简单地返回它的调用,如下所示:

@Benchmark
@Fork(5)
public int bmHashMap(SOExample.Data data) {
    return data.hashmap.get(data.key); // where key is a random generated possible key
}