Why is Arrays.equals(char[], char[]) 8 times faster than all the other versions?

前端 未结 3 549
失恋的感觉
失恋的感觉 2021-02-02 10:31

Short Story

Based on my tests with a few different Oracle and OpenJDK implementations, it seems that Arrays.equals(char[], char[]) is somehow about 8 times fas

3条回答
  •  萌比男神i
    2021-02-02 11:23

    @Marco13 guess was right. HotSpot JVM has an intrinsic (i.e. special hand-coded implementation) forArrays.equals(char[], char[]), but not for other Arrays.equals methods.

    The following JMH benchmark proves that disabling this intrinsic makes char[] array comparsion as slow as short[] array comparison.

    @State(Scope.Benchmark)
    public class ArrayEquals {
        @Param("100")
        int length;
    
        short[] s1, s2;
        char[] c1, c2;
    
        @Setup
        public void setup() {
            s1 = new short[length];
            s2 = new short[length];
            c1 = new char[length];
            c2 = new char[length];
        }
    
        @Benchmark
        public boolean chars() {
            return Arrays.equals(c1, c2);
        }
    
        @Benchmark
        @Fork(jvmArgsAppend = {"-XX:+UnlockDiagnosticVMOptions", "-XX:DisableIntrinsic=_equalsC"})
        public boolean charsNoIntrinsic() {
            return Arrays.equals(c1, c2);
        }
    
        @Benchmark
        public boolean shorts() {
            return Arrays.equals(s1, s2);
        }
    }
    

    Results:

    Benchmark                     (length)  Mode  Cnt   Score   Error  Units
    ArrayEquals.chars                  100  avgt   10  19,012 ± 1,204  ns/op
    ArrayEquals.charsNoIntrinsic       100  avgt   10  49,495 ± 0,682  ns/op
    ArrayEquals.shorts                 100  avgt   10  49,566 ± 0,815  ns/op
    

    This intrinsic was added long ago in 2008 in the times of aggressive JVM competition. JDK 6 included a special alt-string.jar library which was enabled by -XX:+UseStringCache. I've found a number of calls to Arrays.equals(char[], char[]) from one of these special classes - StringValue.StringCache. The intrinsic was an essential part of this "optimization". In modern JDK there is no more alt-string.jar, but JVM intrinsic is still there (not playing its original role though).

    Update

    I've tested the same with JDK 9-ea+148, and it appears that _equalsC intrinsic makes very little performance difference.

    Benchmark                     (length)  Mode  Cnt   Score   Error  Units
    ArrayEquals.chars                  100  avgt   10  18,931 ± 0,061  ns/op
    ArrayEquals.charsNoIntrinsic       100  avgt   10  19,616 ± 0,063  ns/op
    ArrayEquals.shorts                 100  avgt   10  19,753 ± 0,080  ns/op
    

    Arrays.equals implementation has changed in JDK 9.

    Now it calls ArraysSupport.vectorizedMismatch helper method for all types of non-object arrays. Furthermore, vectorizedMismatch is also a HotSpot intrinsic which has hand-written assembly implementation that uses AVX.

提交回复
热议问题