2012-09-01 10 views
8

Estoy en el proceso de transferir un determinado algoritmo de procesamiento de datos de Java a C++. La razón para volver a escribir el código es la portabilidad, necesita ejecutarse en entornos donde Java no está disponible. Sin embargo, como beneficio adicional, se esperaba una mejora en el rendimiento.¿Qué tan caro es .getClass() en Java?

Básicamente, el algoritmo lee datos de un gráfico formado por objetos con punteros entre sí y luego calcula un resultado. Durante el cálculo, se realizan numerosas asignaciones de objetos, por lo que quizás esto sea responsable de la desaceleración. El caso es que el código C++ actualmente se ejecuta aproximadamente 10 veces más rápido que el código Java anterior. Esto fue realmente inesperado. Solo pensé que vería una mejora de tal vez 50-60%.

Lamentablemente, no estoy en libertad de publicar el código aquí para su análisis. Son varios miles de líneas, así que no estoy seguro de lo conveniente que sería de todos modos.

El problema es que el algoritmo es casi exactamente el mismo. La única gran diferencia que puedo pensar es que en Java hay muchas clases hijas de una sola superclase y si (object.getClass() == daughterx.class) se llama muchas veces durante el cálculo, mientras que en el código C++ solo una general se usa la clase (ya que hay pocas diferencias de código entre las clases hijas) y se usa una comparación de números enteros simples, por ejemplo. if (object-> type == 15)

¿Qué tan caro es el método Object.getClass() en Java? ¿Qué está sucediendo exactamente en el nivel bajo cuando se invoca este método?

+5

@ xlc0212 Tampoco lo son cualquiera de las otras personas que no entienden de Java ! ;) – cheeken

+0

@cheeken depende de la JVM, sin JIT, recuerdo que leí en alguna parte que Java es incluso más lento que python –

+3

Honestamente, esto no parece ser un problema. ¿Vale la pena dedicar tiempo a la evaluación comparativa y al perfil de su código obsoleto? A menos que haya hecho eso, no hay manera de saber que '.getClass()' es el cuello de botella. Adivinar no es una forma útil de depurar problemas de rendimiento, a menos que pueda reducir significativamente la complejidad general de un algoritmo (es decir, pasar de una operación N-cuadrado a una operación log-N), y su conjunto de datos es muy grande. –

Respuesta

7

El caso más probable para una diferencia de 10x es que la JVM no se calentó por completo. Si no lo hace, puede ver más de 10 veces la diferencia de rendimiento, incluso en Java. Intentaría correr en lotes de 10.000 e ignoraría las primeras carreras.

public static void main(String... args) throws IOException { 
    timeObjectGraph("First run", 1); 
    timeObjectGraph("Second run", 2); 
    timeObjectGraph("Next thousand", 1000); 
    for (int i = 0; i < 5; i++) 
     timeObjectGraph("Next ten thousand", 10000); 
} 

static int dontOptimiseAway = 0; 

public static void timeObjectGraph(String desc, int runs) throws IOException { 
    long start = System.nanoTime(); 
    for (int i = 0; i < runs; i++) { 
     ByteArrayOutputStream out = new ByteArrayOutputStream(); 
     ObjectOutputStream oos = new ObjectOutputStream(out); 
     oos.writeObject(Calendar.getInstance()); 
     oos.close(); 
     dontOptimiseAway = out.toByteArray().length; 
    } 
    long time = System.nanoTime() - start; 
    System.out.printf("%s took an avg time of %,d ns%n", desc, time/runs); 
} 

impresiones

First run took an avg time of 37,509,488 ns 
Second run took an avg time of 439,054 ns 
Next thousand took an avg time of 185,242 ns 
Next ten thousand took an avg time of 41,698 ns 
Next ten thousand took an avg time of 19,981 ns 
Next ten thousand took an avg time of 11,541 ns 
Next ten thousand took an avg time of 13,451 ns 
Next ten thousand took an avg time of 11,289 ns 

Desde la primera hasta la última carrera, el rendimiento ha mejorado en un factor de 3000x

+0

¿Por qué usa Calendar.getInstance()? Primero, la pregunta es sobre el método getClass. El segundo calendario es ** pesado ** para crear, por lo que Calendar.getInstance() ** es caro por sí mismo **, no porque getClass se llame dentro. Creo que este ejemplo no es correcto o debería proporcionar un comentario más claro. – Cherry

+2

@Cherry Usé Calendar y ObjectOutputStream, ya que ambos son caros para una pieza corta de código, esto brinda un ejemplo realista de cuánto puede hacer la diferencia de calentamiento para una cantidad significativa de código. –

5

No es probable que sea el único factor en la diferencia de rendimiento. Desafortunadamente, sin una imagen mucho más completa de lo que realmente hace tu código, será muy difícil decirte lo que está pasando.

En mi experiencia, no hay ninguna razón por la que Java deba ser 10 veces más lenta que C++. Probablemente comenzaría con un generador de perfiles y vería dónde apunta para comprender el problema, en lugar de adivinar.

11

¿Qué tan caro es el método Object.getClass() en Java?

Basado en mi conocimiento de cómo se implementa en las JVM no convencionales, es barato

Lo que está ocurriendo exactamente en el bajo nivel cuando se invoca este método?

Típicamente ...

  1. Extraer el índice de clase de la cabecera del objeto (2 o 3) instrucciones
  2. de búsqueda el descriptor de clase desde el índice de clase (2 o 3) instrucciones
  3. Busque y devuelva la referencia de objeto Class del descriptor de clase (2 o 3 instrucciones)

El hecho es que el código C++ actualmente se ejecuta aproximadamente 10 veces más rápido que el código Java anterior.

Espero que el cuello de botella de rendimiento esté en otro lugar. Debería intentar crear un perfil del código Java antes de llegar a ninguna conclusión sobre por qué fue más lento.

+6

+1 Si bien la búsqueda en sí misma es barata, implica un problema importante de diseño y rendimiento si tiene secuencias de 'if (getClass() == SomeClass.class)' Sugiere que necesita más OO Design o como lo hizo OP, combine estas clases para que pueda usar un interruptor o similar para la funcionalidad. –

Cuestiones relacionadas