2010-12-23 30 views
13

Duplicar posible:
JIT compiler vs offline compilerscuando es Java más rápido que C++ (o cuando JIT es más rápido que precompilado)?

he oído que, en determinadas circunstancias, los programas Java o más bien partes de los programas Java son capaces de ejecutar más rápido que el "mismo" código en C++ (u otro código precompilado) debido a optimizaciones de JIT. Esto se debe a que el compilador puede determinar el alcance de algunas variables, evitar algunos condicionales y extraer trucos similares en el tiempo de ejecución.

¿Podría dar un (o mejor - algún) ejemplo, donde esto aplica? ¿Y quizás delinear las condiciones exactas bajo las cuales el compilador puede optimizar el bytecode más allá de lo que es posible con el código precompilado?

NOTA: Esta pregunta es no acerca de la comparación de Java a C++. Se trata de las posibilidades de compilación de JIT. Por favor, no flamear. Tampoco estoy al tanto de ningún duplicado. Por favor indíquelos si es así.

+0

este resulta ser un duplicado. Lo siento por los inconvenientes ocasionados. Por favor, combine – kostja

Respuesta

33

En la práctica, es muy probable que encontrar su código Java ingenuamente escrita superan su código escrito en C++, ingenuamente, en estas situaciones (todos los cuales he observado personalmente):

  • Un montón de pequeñas asignaciones de memoria/desasociaciones. Las principales JVM tienen subsistemas de memoria extremadamente eficientes, y la recolección de basura puede ser más eficiente que requerir la liberación explícita (además puede cambiar las direcciones de memoria y tal si realmente lo desea).

  • Acceso eficiente a través de jerarquías profundas de llamadas a métodos. La JVM es muy buena para eliminar cualquier cosa que no sea necesaria, generalmente mejor en mi experiencia que la mayoría de los compiladores de C++ (incluidos gcc e icc). En parte, esto se debe a que puede realizar análisis dinámicos en tiempo de ejecución (es decir, puede optimizar en exceso y solo desoptimizar si detecta un problema).

  • Encapsulación de la funcionalidad en pequeños objetos efímeros.

En cada caso, si se pone el esfuerzo en, C++ puede hacer mejor (entre las listas libres y/memoria desasignado bloque asignado, C++ se puede superar el sistema de memoria de JVM en casi cada caso específico, con código adicional , plantillas y macros inteligentes, puede colapsar las pilas de llamadas de manera muy efectiva, y puede tener pequeños objetos parcialmente inicializados asignados a la pila en C++ que superan el modelo de objetos efímeros de la JVM). Pero probablemente no desee esforzarse.

+1

gracias. este es el nivel de detalle que esperaba. – kostja

5

Wikipedia: http://en.wikipedia.org/wiki/Just-in-time_compilation#Overview

Además, puede en algunos casos oferta mejor rendimiento que la compilación estática, como muchas optimizaciones sólo son factibles en tiempo de ejecución:

  1. La compilación puede ser optimizada para la CPU de destino y el modelo de sistema operativo donde se ejecuta la aplicación. Por ejemplo, JIT puede elegir instrucciones de la CPU SSE2 cuando detecta que la CPU las admite. Para obtener este nivel de especificidad de optimización con un compilador estático, uno debe compilar un binario para cada plataforma/arquitectura deseada, o bien incluir múltiples versiones de partes del código dentro de un solo binario.

  2. El sistema es capaz de recoger estadísticas acerca de cómo el programa se está ejecutando en el entorno donde se encuentra, y puede reorganizar y volver a compilar para óptimo rendimiento. Sin embargo, algunos compiladores estáticos también pueden tomar información de perfil como entrada.

  3. El sistema puede hacer optimizaciones de código globales (inlining por ejemplo, de funciones de la biblioteca) sin perder las ventajas de la vinculación dinámica y sin los gastos generales inherentes a los compiladores estáticos y enlazadores. Específicamente, al realizar sustituciones en línea globales, un proceso de compilación estática puede necesitar comprobaciones en tiempo de ejecución y garantizar que se produciría una llamada virtual si la clase real del objeto anula el método en línea, y es posible que las comprobaciones de condición de frontera en los accesos a la matriz ser procesado dentro de los bucles. Con la compilación just-in-time en muchos casos , este procesamiento se puede mover fuera de los bucles, a menudo dando grandes aumentos de velocidad.

  4. Aunque esto es posible con lenguajes compilados estáticamente recogida de basura, un sistema de código de bytes puede más fácilmente rearrange código ejecutado para una mejor utilización de caché.

+3

Gran información, pero leer de cerca revela que la precompilación en realidad puede y hace muchas de las optimizaciones "solo JIT". –

+1

@BenVoigt Ese es un buen punto. El principal argumento restante es que el JIT tiene acceso a información específica del proceso en ejecución, en lugar de un perfil creado previamente o similar. Por lo tanto, puede realizar optimizaciones audaces con más frecuencia y con mayores posibilidades de éxito. –

6

Algunos ejemplos:

  • El compilador JIT puede producir código máquina muy específico de la CPU usando, por ejemplo las extensiones de SSE más nuevas que uno no usaría en el código precompilado que necesita ejecutar una amplia gama de CPU.
  • El JIT sabe cuándo un método virtual (el valor predeterminado en Java) no se sobrescribe en ningún lugar, y por lo tanto puede estar en línea (aunque esto requiere la capacidad de des-alinearlo cuando se carga una nueva clase que sobrescribe el método; Los compiladores Java JIT realmente hacen esto).
  • Relacionado con eso, escape analysis permite varias optimizaciones específicas de la situación.
+0

El primer punto es adicionalmente válido ya que muchas bibliotecas Java estaban escritas antes de que las nuevas arquitecturas de CPU estuvieran disponibles. Estas bibliotecas antiguas todavía hacen uso de las últimas mejoras de CPu. Para utilizar la última arquitectura en C++, debe poder compilar desde el código fuente, lo que no es posible/práctico con bibliotecas de terceros. esp. si el desarrollador no es el usuario final. p.ej. usted tiene una aplicación que debe implementarse en muchos tipos diferentes de PC, puede ser una pesadilla liberar todas las plataformas posibles, por lo que a menudo se elige el denominador común más bajo. –

+0

Creo que el JIT puede realizar polimorfismo en línea. yo.e conoce hasta dos posibles métodos "virtuales" que suelen denominarse, y estos pueden estar subrayados y, si el objeto no es una de estas clases, hay un retroceso. Esto significa que incluso los métodos virtuales con múltiples implementaciones posibles se pueden alinear en función del comportamiento en tiempo de ejecución. –

+1

Los optimizadores guiados por perfil de C++ utilizan estos mismos trucos. –

0

La gestión de la memoria de Java es considerablemente más rápida que la de C++. Ver Java theory and practice: Urban performance legends, revisited.

+0

un buen enlace a veces es tan bueno como una respuesta puede obtener. muy perspicaz. gracias – kostja

+5

Niza argumento hombre de paja. C++ no requiere que use 'malloc', consulte por ejemplo el asignador de grupos de wireshark. –

+0

por lo que el argumento no se aplica a la asignación de C++ con new entonces? ¿Es porque el montón asignado por HeapAlloc y por igual se usa para asignación con nuevo? – kostja

Cuestiones relacionadas