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
@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.