Parece que estás haciendo dos preguntas bastante diferentes:
- ¿Java es realmente lento, y si es así, por qué?
- ¿Por qué se percibe a Java como lento, aunque es más rápido que muchas alternativas?
La primera de ellas es más o menos una pregunta de "cuánto dura una cuerda". Se reduce a su definición de "lento". En comparación con un intérprete puro, Java es extremadamente rápido. En comparación con otros lenguajes que (normalmente) se compilan en algún tipo de código de bytes, luego se compilan dinámicamente en código máquina (por ejemplo, C # o cualquier otra cosa en .NET) Java está más o menos a la par. En comparación con los lenguajes que normalmente se compilan con código de máquina puro, y tienen equipos (a menudo grandes) de personas que trabajan en nada más que mejorar sus optimizadores (por ejemplo, C, C ++, Fortran, Ada) Java funciona bastante bien en algunas cosas, pero en general tiende a ser al menos algo más lento.
Mucho de esto está relacionado principalmente con la implementación; básicamente, se reduce al hecho de que un usuario está esperando mientras se ejecuta un compilador dinámico / JIT, por lo que, a menos que tenga un programa que se ejecute durante bastante tiempo, es Es difícil justificar que el compilador dedique mucho tiempo a optimizaciones difíciles. Por lo tanto, la mayoría de los compiladores de Java (y C #, etc.) no ponen mucho esfuerzo en optimizaciones realmente difíciles. En muchos casos, se trata menos de qué optimizaciones se realizan, que de dónde se aplican. Muchos problemas de optimización son NP completos, por lo que el tiempo que tardan crece rápidamente con el tamaño del problema que se está atacando. Una forma de mantener el tiempo dentro de lo razonable es aplicar solo la optimización a algo así como una sola función a la vez. Cuando solo el desarrollador espera el compilador, puede permitirse el lujo de tomar mucho más tiempo y aplicar esa misma optimización a fragmentos mucho más grandes del programa. Del mismo modo, el código para algunas optimizaciones es bastante complicado (y, por lo tanto, puede ser bastante grande). Nuevamente, dado que el usuario está esperando mientras se carga ese código (y el tiempo de inicio de JVM es a menudo un factor significativo en el tiempo general), la implementación tiene que equilibrar el tiempo ahorrado en un lugar versus el perdido en otro, y dado el poco código se beneficia de las optimizaciones peludas, por lo general, mantener el JVM pequeño es más beneficioso.
Un segundo problema es que con Java, con frecuencia se obtiene una solución más o menos "única para todos". Solo por ejemplo, para muchos desarrolladores de Java Swing es esencialmente la única biblioteca de ventanas disponible. En algo como C ++, hay literalmente docenas de bibliotecas de ventanas, marcos de aplicaciones, etc., cada uno con su propio conjunto de compromisos entre facilidad de uso frente a ejecución rápida, aspecto y sensación coherentes frente a aspecto y sensación nativos, y así sucesivamente. El único punto de fricción real es que algunos (por ejemplo, Qt) pueden ser bastante caros (al menos para uso comercial).
Tercero, una gran cantidad de código escrito en C ++ (y C aún más) es simplemente más antiguo y más maduro. En gran parte contiene un núcleo de rutinas escritas hace décadas, cuando pasar tiempo extra optimizando el código era un comportamiento normal y esperado. Eso a menudo tiene un beneficio real en código que es más pequeño y más rápido. C ++ (o C) obtiene el crédito de que el código es pequeño y rápido, pero en realidad es mucho más un producto del desarrollador y las limitaciones del tiempo en que se escribió el código. Hasta cierto punto, esto lleva a una profecía autocumplida: cuando las personas se preocupan por la velocidad, a menudo seleccionan C ++ porque tiene esa reputación. Dedican más tiempo y esfuerzo a la optimización, y se escribe una nueva generación de código C ++ rápido.
Para resumir, la implementación normal de Java hace que la optimización máxima sea problemática en el mejor de los casos. Peor aún, cuando Java es visible , cosas como los juegos de herramientas de ventanas y el tiempo de inicio de JVM a menudo juegan un papel más importante que la velocidad de ejecución del lenguaje de todos modos. En muchos casos, C y C ++ también obtienen crédito por lo que realmente es el producto de simplemente trabajar más duro en la optimización.
En cuanto a la segunda pregunta, creo que es en gran medida una cuestión de naturaleza humana en el trabajo. Algunos fanáticos hacen afirmaciones bastante infladas acerca de que Java es cegadoramente rápido. Alguien lo prueba y descubre que incluso un programa trivial tarda unos segundos en comenzar, y se siente lento y torpe cuando se ejecuta. Probablemente pocos se molesten en analizar las cosas para darse cuenta de que gran parte de esto es el tiempo de inicio de la JVM, y el hecho de que cuando prueban por primera vez, ninguno de los códigos se ha compilado todavía; parte del código se está interpretando, y algunos se compilan mientras esperan. Peor aún, incluso cuando se ejecuta lo suficientemente rápido, el aspecto y la sensación generalmente parecerán extraños y torpes para la mayoría de los usuarios, por lo que incluso si las mediciones objetivas mostraron tiempos de respuesta rápidos, aún parecería torpe.
Agregarlos juntos lleva a una reacción bastante simple y natural: que Java es lento, feo y torpe. Dado el bombo publicitario que dice que es realmente rápido, hay una tendencia a reaccionar de forma exagerada y concluir pensar que es terriblemente lento, en lugar de un (más preciso) "un poco más lento, y eso principalmente en circunstancias específicas". Esto generalmente es peor para un desarrollador que escribe los primeros programas en el idioma. La ejecución de un programa "hello world" en la mayoría de los idiomas parece instantánea, pero en Java hay una pausa fácilmente perceptible cuando se inicia la JVM. Incluso un intérprete puro que se ejecuta mucho más lentamente en bucles estrechos y aún así a menudo aparecerá más rápido para un código como este, simplemente porque puede cargarse y comenzar a ejecutarse un poco antes.