InstanceOf Performance
The following is a microbenchmark to test the performance of the Java instanceOf operation. The four dispatch methods tested are:
- InstanceOf operator
- Comparing class objects using ==
- Using polymorphism to dispatch
- Embedding a type id into each class.
<geshi lang="java"> package org.egge;
public class InstanceOf {
private static final int REPS = 1000000000;
private enum Type { A, B };
private static abstract class Base { int sum; final Type type;
public Base(Type type) { this.type = type; }
public abstract void doSomthing(); }
private static class A extends Base { public A() { super(Type.A); }
public void doA() { sum += 2; }
@Override public void doSomthing() { sum += 2; } }
private static class B extends Base { public B() { super(Type.B); }
public void doB() { sum -= 2; }
@Override public void doSomthing() { sum -= 2; } }
public static void main(String[] args) { for (int i = 0; i < 5; i++) { System.out.println("Rep " + i); for (Type t : Type.values()) { Base base; if (t == Type.A) { base = new A(); } else { base = new B(); } testInstanceOf(base); testIsClass(base); testOO(base); testId(base); } } }
private static void testInstanceOf(Base base) { long start = System.currentTimeMillis(); for (int i = 0; i < REPS; i++) { if (base instanceof A) { ((A) base).doA(); } else if (base instanceof B) { ((B) base).doB(); } else { throw new RuntimeException(); } } long diff = System.currentTimeMillis() - start; System.out.println("InstanceOf " + diff + " " + base.sum); }
private static void testOO(Base base) { long start = System.currentTimeMillis(); for (int i = 0; i < REPS; i++) { base.doSomthing(); } long diff = System.currentTimeMillis() - start; System.out.println("OO " + diff + " " + base.sum); }
private static void testId(Base base) { long start = System.currentTimeMillis(); for (int i = 0; i < REPS; i++) { switch (base.type) { case A: ((A) base).doA(); break; case B: ((B) base).doB(); break; default: throw new RuntimeException(); } } long diff = System.currentTimeMillis() - start; System.out.println("Id " + diff + " " + base.sum); }
private static void testIsClass(Base base) { long start = System.currentTimeMillis(); for (int i = 0; i < REPS; i++) { if (base.getClass() == A.class) { ((A) base).doA(); } else if (base.getClass() == B.class) { ((B) base).doB(); } else { throw new RuntimeException(); } } long diff = System.currentTimeMillis() - start; System.out.println("class== " + diff + " " + base.sum); }
} </geshi>
The results are significantly different when running on a Solaris server JVM vs a Windows client JVM. On the server, the results of the four methods are nearly identical. The interesting thing with the server is the first iteration runs very quickly. This is because only one type has been loaded at that point and the operations can easily be optimized, and there's only one possible path. The results on Windows, show the fastest method is comparing class objects, then instanceof, then polymorphism, and lastly the type id.
Results
<geshi> Windows: InstanceOf 6141 class== 3312 OO 8547 Id 9953
Solaris first: InstanceOf 121 class== 122 OO 114 Id 119
Solaris last: InstanceOf 3156 class== 2925 OO 3083 Id 3067 </geshi>