How is instanceof implemented in modern JVM implementations?

人盡茶涼 提交于 2019-12-02 01:03:22

AFAIK each class knows all the classes it extends and interfaces it implements. These could be stored in a hash set giving O(1) lookup time.

When code often takes the same branch, the cost can be almost eliminated as the CPU can execute the code in the branch before it has determined whether it should take the branch making the cost next to nothing.

As the micro-benchmark was performed 4 years ago, I expect the latest CPUs and JVMs to be much faster.

public static void main(String... args) {
    Object[] doubles = new Object[100000];
    Arrays.fill(doubles, 0.0);
    doubles[100] = null;
    doubles[1000] = null;
    for (int i = 0; i < 6; i++) {
        testSameClass(doubles);
        testSuperClass(doubles);
        testInterface(doubles);
    }
}

private static int testSameClass(Object[] doubles) {
    long start = System.nanoTime();
    int count = 0;
    for (Object d : doubles) {
        if (d instanceof Double)
            count++;
    }
    long time = System.nanoTime() - start;
    System.out.printf("instanceof Double took an average of %.1f ns%n", 1.0 * time / doubles.length);
    return count;
}

private static int testSuperClass(Object[] doubles) {
    long start = System.nanoTime();
    int count = 0;
    for (Object d : doubles) {
        if (d instanceof Number)
            count++;
    }
    long time = System.nanoTime() - start;
    System.out.printf("instanceof Number took an average of %.1f ns%n", 1.0 * time / doubles.length);
    return count;
}

private static int testInterface(Object[] doubles) {
    long start = System.nanoTime();
    int count = 0;
    for (Object d : doubles) {
        if (d instanceof Serializable)
            count++;
    }
    long time = System.nanoTime() - start;
    System.out.printf("instanceof Serializable took an average of %.1f ns%n", 1.0 * time / doubles.length);
    return count;
}

finally prints

instanceof Double took an average of 1.3 ns
instanceof Number took an average of 1.3 ns
instanceof Serializable took an average of 1.3 ns

if I change the "doubles" with

    for(int i=0;i<doubles.length;i+=2)
        doubles[i] = "";

I get

instanceof Double took an average of 1.3 ns
instanceof Number took an average of 1.6 ns
instanceof Serializable took an average of 2.2 ns

Note: If I change

if (d instanceof Double)

to

if (d != null && d.getClass() == Double.class)

the performance was the same.

I don't know how this is handled, but you could find out by looking at the source code of the JIT compiler, or by dumping the JIT compiled native code for some examples.

And how is class loading handled? Loading new subclasses means that a lot of intervals have to be adjusted.

There are a few situations where the JIT compiler optimizes based on the assumption that the current set of loaded classes is all that there are. If new classes are loaded, I understand that the compiler marks the affected JIT-compiled classes as needing to be recompiled.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!