2012-09-12 2 views
2

다른 스레드에서 수행 된 벤치 마크 (cf. https://stackoverflow.com/a/397617/1408611 참조)로 인해 Java 6의 instanceof가 실제로 매우 빠르다는 것이 나타났습니다. 어떻게 이루어 집니까?instanceof는 최신 JVM 구현에서 어떻게 구현됩니까?

단일 상속의 경우 가장 빠른 아이디어는 각 클래스가 [낮음, 높음] 간격을 유지하는 중첩 된 간격 인코딩을 갖는 것입니다. 인스턴스는 단순히 간격 포함 테스트, 즉 2 개의 정수 비교입니다. 그러나 인터페이 스용 (인터벌 포함은 단일 상속에서만 작동합니다) 어떻게 만들어 졌습니까? 클래스 로딩은 어떻게 처리됩니까? 새 하위 클래스로드는 많은 간격을 조정해야한다는 것을 의미합니다.

답변

4

AFAIK 각 클래스는 자신이 확장하고 인터페이스를 구현하는 모든 클래스를 알고 있습니다. 이것들은 O (1) 검색 시간을 제공하는 해시 세트에 저장 될 수 있습니다.

코드가 자주 동일한 분기를 사용하는 경우 CPU가 분기에서 코드를 실행하기 전에 비용을 거의 없앨 수 있으므로 비용을 없애는 분기를 사용해야하는지 여부가 결정됩니다.

마이크로 벤치 마크가 4 년 전에 수행 되었기 때문에 최신 CPU와 JVM이 훨씬 더 빠를 것으로 기대합니다. 내가

0,123,516을 변경하는 경우 : 나는

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

으로 "더블"을 변경하는 경우

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; 
} 

마침내 내가

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 

을 얻을

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 (d instanceof Double) 

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

에 성능과 동일하다.

+0

또한이 해시 테이블 접근 방식에 대해서도 생각하고있었습니다. 그러나 instanceof는 해시 테이블 조회보다 더 빠른 경우도 있습니다. 매개 변수가없는 단일 함수 호출보다 훨씬 빠릅니다. – gexicide

+0

생성 된 코드는 인라인 될 수 있습니다. 위의'Double'의 경우, 클래스가'final'이므로 테스트는'd! = null && d.getClass() == Double.class'와 동일합니다. –

0

어떻게 처리해야할지 모르지만 JIT 컴파일러의 소스 코드를 보거나 JIT 컴파일 원시 코드를 덤프하여 찾을 수 있습니다.

클래스로드는 어떻게 처리됩니까? 새 하위 클래스로드는 많은 간격을 조정해야한다는 것을 의미합니다.

JIT 컴파일러가 현재로드 된 클래스 집합이 모두 있다는 가정에 따라 최적화되는 경우가 있습니다. 새 클래스가로드되면 컴파일러가 영향을받는 JIT 컴파일 클래스를 다시 컴파일해야한다고 표시합니다.