¿Java es realmente lento?

180

Java tiene cierto grado de reputación por ser lento .

  • ¿Java es realmente lento?
  • ¿Si es así por qué? ¿Dónde está (o estaba) el cuello de botella? ¿Es por JVM ineficientes? ¿Recolección de basura? ¿Bibliotecas de código de bytes puro en lugar de código C envuelto en JNI? Muchos otros idiomas tienen estas características, pero no tienen esta reputación de lentitud.
Stefano Borini
fuente
35
la gente se pone tan nerviosa ... no veo cómo esto puede ser subjetivo, ni es discutidor. Me pregunto si una pregunta como "por qué la clasificación de burbujas es lenta" obtendría el mismo resultado. Hice una pregunta técnica y quería respuestas técnicas (que obtuve), pero cerrar la pregunta como subjetiva y argumentativa es ridículo.
Stefano Borini
1
He leído la mayoría de los comentarios principales y ninguno de ellos parece abordar el hecho evidente de que las aplicaciones de escritorio basadas en GUI de C # se ejecutan mucho más rápido que cualquier aplicación de escritorio basada en GUI de Java, incluidas las modernas.
BobTurbo
3
Como desarrollador web del lado del cliente que se ha ocupado de las formas web .net, .net MVC, PHP, Rails, Django y una amplia variedad de todo menos Spring (que he escuchado es bueno) en Java, espero un bajo rendimiento / arquitectura desde back-end construidos por equipos Java. Sospecho que el verdadero problema no son los puntos de referencia, sino el problema de que simplemente haya una tonelada de desarrolladores Java mediocres. Eso no es culpa del idioma. No es culpa de los desarrolladores de Java que realmente perfeccionan su oficio y aprenden otros idiomas además de Java. Sin embargo, puede ser culpa de Sun, los certificados, los años 90 y la industria de TI en general.
Erik Reppen

Respuestas:

236

El Java moderno es uno de los lenguajes más rápidos, a pesar de que todavía es un cerdo de memoria. Java tenía fama de ser lento porque la VM tardaba mucho tiempo en iniciarse.

Si todavía crees que Java es lento , mira los resultados del juego de puntos de referencia . El código estrictamente optimizado escrito en un lenguaje compilado antes de tiempo (C, Fortran, etc.) puede superarlo; sin embargo, Java puede ser más de 10 veces más rápido que PHP, Ruby, Python, etc. Existen áreas específicas donde puede vencer a los lenguajes compilados comunes (si usan bibliotecas estándar).

No hay excusa para las aplicaciones Java "lentas" ahora. Los desarrolladores y las bibliotecas / códigos heredados son los culpables, mucho más que el lenguaje. Además, culpe a todo 'empresa'.

Para ser justos con la multitud "Java es lento", aquí hay áreas donde todavía es lento (actualizado para 2013):

  • Las bibliotecas a menudo se escriben para "corrección" y legibilidad, no para rendimiento. En mi opinión, esta es la razón principal por la que Java todavía tiene una mala reputación, especialmente en el lado del servidor. Esto hace que los problemas de String sean exponencialmente peores. Algunos errores simples son comunes: los objetos a menudo se usan en lugar de primitivos, lo que reduce el rendimiento y aumenta el uso de la memoria. Muchas bibliotecas Java (incluidas las estándar) crearán cadenas con frecuencia, en lugar de reutilizar formatos mutables o más simples (char [] o StringBuffer). Esto es lento y crea toneladas de basura para recolectar más tarde. Para solucionar esto, sugiero que los desarrolladores utilicen colecciones primitivas y especialmente las bibliotecas de Javalution, siempre que sea posible.

  • Las operaciones de cadena son un poco lentas. Java utiliza objetos de cadena codificados con UTF-16 inmutables. Esto significa que necesita más memoria, más acceso a la memoria y algunas operaciones son más complejas que con ASCII (C, C ++). En ese momento, era la decisión correcta para la portabilidad, pero conlleva un pequeño costo de rendimiento. UTF-8 parece una mejor opción ahora.

  • El acceso a la matriz es un poco más lento en comparación con C, debido a las comprobaciones de límites. La penalización solía ser grande, pero ahora es pequeña (Java 7 optimiza muchas comprobaciones de límites redundantes).

  • La falta de acceso arbitrario a la memoria puede hacer que algunas E / S y el procesamiento a nivel de bits sean lentos (por ejemplo, compresión / descompresión). Esta es una característica de seguridad de la mayoría de los idiomas de alto nivel ahora.

  • Java usa MUCHA más memoria que C, y si su aplicación está vinculada a la memoria o al ancho de banda de la memoria (almacenamiento en caché, etc.) esto lo hace más lento. La otra cara es que la asignación / desasignación es increíblemente rápida (altamente optimizada). Esta es una característica de la mayoría de los lenguajes de alto nivel ahora, y se debe a los objetos y al uso de GC en lugar de la asignación explícita de memoria. Más malas decisiones de la biblioteca.

  • La E / S basada en secuencias es lenta debido a que (IMO, mala elección) requiere sincronización en el acceso de cada secuencia. NIO solucionó esto, pero es difícil de usar. Se puede evitar esto haciendo lectura / escritura en una matriz, en lugar de un elemento a la vez.

  • Java no proporciona la misma funcionalidad de bajo nivel que C, por lo que no puede usar trucos sucios de ensamblador en línea para acelerar algunas operaciones. Esto proporciona portabilidad y es una característica de la mayoría de los idiomas de alto nivel ahora.

  • Es común ver aplicaciones Java vinculadas a versiones JVM muy antiguas. Especialmente del lado del servidor. Estas viejas JVM pueden ser increíblemente ineficientes, en comparación con las últimas versiones.

Al final, Java fue diseñado para proporcionar seguridad y portabilidad a expensas de cierto rendimiento y para algunas operaciones realmente exigentes. La mayor parte de su reputación de lentitud ya no se merece.


Sin embargo, hay varios lugares donde Java es más rápido que la mayoría de los otros idiomas:

  • La asignación de memoria y la desasignación son rápidas y baratas. He visto casos en los que es 20% MÁS RÁPIDO (¡o más!) Asignar una nueva matriz de varios KB que reutilizar una en caché.

  • La creación de instancias de objetos y las funciones orientadas a objetos son extremadamente rápidas de usar (más rápido que C ++ en algunos casos), porque están diseñadas desde el principio. Esto se debe en parte a un buen GC en lugar de una asignación explícita (que es más amigable con muchas asignaciones de objetos pequeños). Uno puede codificar C que supera esto (mediante la administración de memoria personalizada y haciendo malloc de manera eficiente), pero no es fácil.

  • Las llamadas a métodos son básicamente gratuitas y, en algunos casos, más rápidas que el código de método grande. El compilador HotSpot utiliza información de ejecución para optimizar las llamadas a métodos y tiene una alineación muy eficiente. Al utilizar la información de ejecución adicional, a veces puede superar a los compiladores anticipados e incluso (en casos excepcionales) la inserción manual. Compare con C / C ++ donde las llamadas a métodos tienen una pequeña penalización de rendimiento si el compilador decide no conectarse.

  • La sincronización y el subprocesamiento múltiple son fáciles y eficientes. Java fue diseñado para ser compatible con hilos desde el principio, y se nota. Las computadoras modernas generalmente cuentan con múltiples núcleos, y debido a que el subproceso está integrado en el lenguaje, puede aprovecharlo muy fácilmente. Básicamente, un aumento adicional de velocidad del 100% al 300% frente al código C estándar de un solo subproceso. Sí, los subprocesos C y las bibliotecas escritas cuidadosamente pueden superar esto, pero eso es mucho trabajo adicional para el programador.

  • Las cadenas incluyen longitud: algunas operaciones son más rápidas. Esto supera el uso de cadenas delimitadas por nulos (comunes en C). En Java 7, Oracle eliminó la optimización String.subString (), porque la gente la usaba estúpidamente y recibía pérdidas de memoria.

  • La copia de matriz está altamente optimizada. En las últimas versiones, Java utiliza ensamblador sintonizado a mano para System.arraycopy. El resultado es que en operaciones de arraycopy / memcopy-heavy, he visto que mi código supera el equivalente en C por márgenes razonables.

  • El compilador JIT es inteligente sobre el uso de caché L1 / L2 . Los programas compilados antes de tiempo no pueden modificar su código en tiempo real para la CPU y el sistema específicos en los que se ejecutan. JIT proporciona algunas transformaciones de bucle muy eficientes de esta manera.

Un par de otros hechos históricos contribuyeron a la reputación de "Java es lento":

  • Antes de la compilación JIT (Java 1.2 / 1.3), el lenguaje solo se interpretaba, no se compilaba y, por lo tanto, era muy lento.
  • La compilación JIT tardó en volverse eficiente (mejoras importantes con cada versión)
  • La carga de clases se ha vuelto mucho más eficiente con los años. Solía ​​ser bastante ineficiente y lento durante el inicio.
  • El código Swing y UI no usaba muy bien el hardware de gráficos nativo.
  • El swing es simplemente horrible. Culpo a AWT y Swing de por qué Java nunca se puso al día con el escritorio.
  • Uso intensivo de sincronización en clases de biblioteca; versiones no sincronizadas ya están disponibles
  • Los applets tardan una eternidad en cargarse porque transmiten un JAR completo a través de la red y cargan la VM para arrancar.
  • La sincronización solía llevar una gran penalización de rendimiento (esto se ha optimizado con cada versión de Java). Sin embargo, la reflexión sigue siendo costosa.
BobMcGee
fuente
49
Object instantiation and object-oriented features are blazing fast to use (faster than C++ in many cases) because they're designed in from the beginning.y Collections are fast. Standard Java beats standard C/C++ in this area, even for most optimized C code.son afirmaciones sin fundamento que no están respaldadas por ninguna evidencia vinculada aquí.
Sjoerd
8
@Sjoerd: las afirmaciones no son descabelladas: son obvias para mí, y deberían serlo para cualquiera que comprenda las diferencias en la arquitectura del sistema de memoria predeterminado en C / C ++ frente a Java. Usted puede hacer mucho mejor aún si usted escribe sus propios controladores de memoria (con cosas como listas libres, grupos de memoria, etc.) o utilizar una biblioteca que implementa este tipo.
Rex Kerr
15
@Rex Kerr: ¿por qué usar controladores de memoria si puede usar, por ejemplo, la pila para la asignación? Está confundiendo la asignación de memoria de montón con la creación de instancias de objeto.
Sjoerd
20
@Rex Kerr: básicamente afirma que, dado que todo en Java implica la asignación de memoria en el montón, y porque la asignación de Java en el montón en Java es más rápida que la de C ++, todo en Java es más rápido. Aquí hay algunas noticias para usted: ¡en C ++ puede hacerlo sin asignar memoria en el montón en muchos casos!
Sjoerd
10
@Sjoerd - ¿Dónde dije que todo en Java es más rápido? Acabo de leer lo que dije. Dije lo que quería decir y ya he abordado todo lo que dijiste en tu último comentario.
Rex Kerr
49

Inicialmente, Java no fue particularmente rápido, pero tampoco es demasiado lento. En estos días, Java es muy rápido. De las personas con las que he hablado, la impresión de que Java es lento proviene de dos cosas:

  1. Tiempo de inicio de VM lento. La implementación inicial de Java tardó mucho tiempo en iniciarse y cargar las bibliotecas requeridas y la aplicación en comparación con las aplicaciones nativas.

  2. IU lenta El swing temprano fue lento. Probablemente tampoco ayudó que la mayoría de los usuarios de Windows encontraran el Metal L&F predeterminado feo.

Teniendo en cuenta los puntos anteriores, no es de extrañar que la gente tenga la impresión de 'Java es lento'.

Para los usuarios o desarrolladores acostumbrados a desarrollar aplicaciones nativas, o incluso aplicaciones de Visual Basic , estos dos puntos son lo más visible en una aplicación, y es la primera impresión que obtendrá sobre una aplicación (a menos que sea una aplicación sin GUI en la que solo se aplica el 1.).

No convencerá a un usuario de que "ejecuta el código muy rápido" cuando la aplicación tarda 8 segundos en iniciarse en comparación con su antigua aplicación de Visual Basic que se inicia de inmediato, aunque la ejecución del código y el tiempo de inicio no estén conectados.

Arruinar la primera impresión es una excelente manera de comenzar rumores y mitos. Y los rumores y los mitos son difíciles de matar.

En resumen, Java no es lento. Las personas que tienen la "actitud lenta de Java" se basan en las primeras impresiones de Java hace más de 10 años.

nos
fuente
3
Java era muy lento hace unos años, pero en las pruebas de referencia recientes se ejecuta casi tan rápido como C / C ++ y en algunas situaciones se ejecuta más rápido.
ChadNC
23
Las aplicaciones Java en OSX 10.6 en mi Macbook comienzan mucho más lentamente que las aplicaciones escritas en Objective-C. ¿Qué evidencia de tiempos de inicio rápidos?
Zan Lynx el
2
La descompresión no es absolutamente un problema de rendimiento. Mi computadora en 1992 descomprimió los ejecutables al iniciar programas que mejoraron el rendimiento al cargar un archivo más largo del disco duro. La disparidad entre la CPU y el disco duro ha crecido enormemente en los últimos años. Sin embargo, hay un problema con el uso del formato de archivo zip para rt.jar (¡¿por qué? !!!) y los archivos de clase contenidos no están vinculados (¡locos!).
Tom Hawtin - tackline
55
@Zan: tenga en cuenta que JVM para Mac OS X está escrito (o al menos adaptado) por Apple. Sun ha invertido bastante tiempo para acelerar los tiempos de inicio en las plataformas que admiten (Windows, Linux y Solaris), pero no pudieron hacerlo para Mac OS x (ya que no mantienen ese puerto). Podría ser que Mac no pudo / no aplicó / transfirió todas esas optimizaciones a Mac OS X.
Joachim Sauer
1
No considero que Java sea lento (sé de un creador de juegos que hace juegos en ellos); simplemente malo por razones de UI. Ni una sola aplicación Java "regular" que he visto tiene una interfaz de usuario decente y completamente funcional.
RCIX
40

Después de leer una página llena de comentarios que dicen que Java no es lento, solo tengo que responder con una opinión diferente.

La lentitud de un idioma depende mucho de cuáles sean sus expectativas de 'rápido'. Si considera que C # es rápido, Java seguramente también lo es. Si su dominio problemático está relacionado con bases de datos o procesamiento semi en tiempo real, Java seguramente también es lo suficientemente rápido. Si está contento de escalar su aplicación agregando más hardware, es probable que Java sea rápido para usted. Si considera que una aceleración de factor constante en la escala de 5-10 no vale la pena, probablemente considere que Java es rápido.

Si realiza un cálculo numérico en grandes conjuntos de datos, o está vinculado a un entorno de ejecución, donde los recursos de la CPU son limitados, donde una aceleración constante en la escala de 5-10 sería enorme. Incluso una aceleración de 0.5 puede significar una reducción de 500 horas para que se complete el cálculo. En estos casos, Java simplemente no le permite obtener ese último nivel de rendimiento, y probablemente consideraría que Java es lento.

Sami
fuente
2
de acuerdo, y +1 en toda la publicación porque presenta un punto válido, sin embargo, C ++, por ejemplo, tiene la fama diferente de ser difícil de depurar y fácil de volar, pero rara vez escuché que C ++ sea tan lento como escuché sobre java.
Stefano Borini
33

Parece que estás haciendo dos preguntas bastante diferentes:

  1. ¿Java es realmente lento, y si es así, por qué?
  2. ¿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.

Jerry Coffin
fuente
16

Es información desactualizada de los primeros días (mediados a fines de la década de 1990) de Java. Cada versión principal de Java ha introducido aceleraciones significativas en comparación con la versión anterior. Con Oracle aparentemente fusionando JRockit con JVM de Sun para Java 7, parece que esta tendencia continuará.

En comparación con muchos otros lenguajes modernos populares (Python, Ruby, PHP), Java es en realidad significativamente más rápido para la mayoría de los usos. No coincide exactamente con C o C ++, pero para muchas tareas está lo suficientemente cerca. Las preocupaciones sobre el rendimiento real deberían ser la cantidad de memoria que termina usando.

Dan Dyer
fuente
14

El principal culpable del "largo tiempo de inicio" es la vinculación dinámica. Una aplicación Java consta de clases compiladas. Cada clase hace referencia a otras clases (para tipos de argumentos, invocaciones de métodos ...) por nombre . La JVM debe examinar y hacer coincidir esos nombres al inicio. Lo hace de forma incremental, haciendo solo las partes que necesita en un momento dado, pero aún queda mucho trabajo por hacer.

En una aplicación C, esa fase de enlace ocurre al final de la compilación. Es lento, especialmente para aplicaciones grandes, pero solo el desarrollador lo ve. La vinculación produce un archivo ejecutable que el sistema operativo simplemente tiene que cargar en la RAM "tal cual".

En Java, el enlace ocurre cada vez que se ejecuta la aplicación. De ahí el largo tiempo de arranque.

Se han aplicado varias optimizaciones, incluidas las técnicas de almacenamiento en caché, y las computadoras se vuelven más rápidas (y se vuelven "más rápidas" que las aplicaciones "más grandes"), por lo que la importancia del problema se ha reducido mucho últimamente; pero el viejo prejuicio permanece.

En cuanto al rendimiento posterior, mis propios puntos de referencia en computaciones compactas con acceso a arreglos (principalmente funciones hash y otros algoritmos criptográficos) generalmente muestran que el código C optimizado es aproximadamente 3 veces más rápido que el código Java; a veces C es solo un 30% más rápido que Java, a veces C puede ser 4 veces más rápido, dependiendo del algoritmo implementado. Vi un factor de 10x cuando el código "C" fue realmente ensamblado para aritmética de enteros grandes, debido a los códigos de multiplicación de 64x64-> 128 que ofrece el procesador pero Java no puede usar porque su tipo entero más largo es el de 64 bits long. Este es un caso extremo. En condiciones prácticas, las consideraciones de E / S y ancho de banda de memoria evitan que el código C sea realmente tres veces más rápido que Java.

Thomas Pornin
fuente
Hmm ... Pensé que la mayoría de las bibliotecas C también estaban vinculadas dinámicamente hoy en día. ¿O estás hablando de algo diferente?
Sean McMillan
44
@Sean: la vinculación dinámica para C se produce para "símbolos externos": las funciones que se utilizan en una DLL y se definen en otra. Una aplicación C típica usará una docena de DLL. Para Java, el enlace dinámico ocurre para todos los métodos en todas las clases: hay miles de ellos en una aplicación Java típica (incluida la biblioteca estándar). En el mundo C, la mayoría de los enlaces (todos los enlaces que no cruzan un límite de DLL) se resuelven en el momento de la compilación, solo queda una pequeña proporción en tiempo de ejecución.
Thomas Pornin
14

Java es definitivamente lento, especialmente para el trabajo cuantitativo.

Utilizo una combinación de R , Python y C / C ++ con bibliotecas ATLAS multiproceso optimizadas . En cada uno de estos idiomas puedo multiplicar por matriz una matriz de dobles de 3000 por 3000 consigo misma en alrededor de 4 segundos. Usando Colt y Parallel Colt en Java, ¡la misma operación toma 185 segundos! Asombroso a pesar de que estas bibliotecas de Java son de naturaleza paralela.

Con todo, Java puro no es adecuado para el trabajo cuantitativo. Jblas parece ser la mejor biblioteca de álgebra lineal para Java, ya que utiliza ATLAS.

Mi maquina es una HP Core 2 Duo con 3 GB de RAM. Yo uso Ubuntu 10.04 de 64 bits (Lucid Lynx).

Hamaad Shah
fuente
Siguiendo mi comentario antes mencionado, realicé la misma operación de multiplicación de matrices usando JAMA y me tomó alrededor de 50 segundos. Todavía es demasiado lento en comparación con otros idiomas.
Hamaad Shah
77
¿Cuánto tiempo tardó Java cuando realizó la multiplicación en las bibliotecas llamadas a través de JNI? Dado que todo lo que puede hacer en C / C ++ puede hacerlo con JNI (agregue unos cientos de mnano-segundos), el margen es relativamente pequeño. Supongo que su multiplicación de matriz R y Python no se escribió en R o Python, solo se llamó desde esos idiomas.
Peter Lawrey
2
Por curiosidad, ¿ha hecho algún perfil para identificar si tiene algún punto de acceso en su código (conversión de tipo / autoboxing)?
Thorbjørn Ravn Andersen
10

Para la experiencia de la mayoría de las personas interactuando con él, Java es lento. Todos hemos visto esa taza de café girando en nuestro navegador antes de que aparezca algún applet. Se tarda un poco en activar la JVM y descargar los binarios del applet, y eso impacta la experiencia del usuario de una manera que se nota.

No ayuda que el lento giro de JVM y el tiempo de descarga de applets estén marcados con una taza de café Java, por lo que la gente asocia la espera con Java. Cuando Flash tarda mucho en cargar, el desarrollador de Flash especifica la marca del mensaje de "carga", por lo que las personas no culpan a la tecnología Flash en su conjunto.

Todo esto no tiene nada que ver con el rendimiento de Java en un servidor, ni con las muchas otras formas en que Java se usa fuera del navegador. Pero es lo que la gente ve y lo que los desarrolladores no Java recuerdan cuando piensan en Java.

Spike Williams
fuente
9

Java tiene la reputación de ser lento porque era lento. Las primeras versiones de Java no tenían una compilación Just In Time o no eran bastante buenas. Esto significaba que el código, aunque el código de bytes, estaba siendo interpretado, por lo que incluso para las operaciones más simples (como agregar dos enteros) la máquina tenía que hacer todo tipo de comparaciones y desreferencias de puntero y llamadas a funciones. El compilador JIT ha mejorado constantemente; ahora es en el punto donde si escribo código C ++ descuidadamente y código Java descuidadamente, Java a veces superará C ++ porque el compilador JIT se da cuenta de que tengo una desreferencia de puntero innecesaria y se encargará de mí.

Si desea ver la diferencia que marca la compilación JIT, consulte los puntos de referencia interpretados frente a los no interpretados en el juego de referencia de idiomas de computadora . (Pidigits usa una biblioteca externa para hacer todos los cálculos, de modo que el punto de referencia no cambie; ¡los otros muestran una aceleración de 6-16x!)

Entonces, esa es la razón principal. Hay una variedad de otras razones menores que no ayudaron: originalmente, el tiempo de inicio de Java era lento (ahora corregido); las aplicaciones web en Java tardan mucho en descargarse (mucho menos cierto ahora con banda ancha ampliamente accesible y con grandes cosas como películas que se esperan); el UI Swing no se escribió (y aún no se tiene) teniendo en cuenta el rendimiento, por lo que es mucho menos ágil que sus equivalentes, por ejemplo, en C ++.

Rex Kerr
fuente
6

Java era lento, en el pasado. Se ha vuelto mucho más rápido, debido a algunas generaciones de mejoras de rendimiento . Lo último que escuché es que generalmente está dentro del 10% de la velocidad de C #, a veces más rápido, a veces más lento.

El inicio del applet de Java todavía es lento porque debes iniciar una JVM completa, que tiene que cargar todas sus clases. Algo así como arrancar otra computadora. Una vez que se inicia el JVM, es bastante rápido, pero el inicio suele ser lo que la gente recuerda.

Además, hay al menos algunas personas que nunca creerán en la viabilidad de Java.

Kaleb Brasee
fuente
1
Lamentablemente, el inicio de JVM sigue siendo mucho más lento que el de CLR. Esto se debe a que Sun ha arrastrado los pies de la peor manera al lanzar Java 7, por lo que estamos atrapados con parches incrementales para Java 6 de 4 años .
BobMcGee
3
Wow, Java 6 tiene 4 años ??? Sí, supongo que sí (si cuentas la beta). Todavía me parece nuevo: dejé de usar 1.4 en el trabajo.
Kaleb Brasee
Java 1.4 es utilizable, pero un poco insufrible, ya que 1.5 y 1.6 agregaron muchos aumentos de rendimiento y azúcar sintáctico. Bounds-check y System.arraycopy optimizaciones se introdujeron desde entonces. También hubo muchas mejoras de sincronización. Creo que es justo decir que 1.4 realmente es lento.
BobMcGee
LOL, lo sé: cada vez que tengo que iterar manualmente o usar una matriz en lugar de una lista genérica, quiero dividir mi computadora portátil a la mitad ... IBM realmente ha tenido Java 5 disponible en WAS 6.1 durante años, pero yo ' he estado atascado en WAS 6.0 :( He estado usando Java 5/6 desde que salió para mis propias cosas, pero estoy limitado por las versiones antiguas del servidor en el trabajo. Hay mejoras de rendimiento de porcentaje de dos dígitos de 1.4 a las versiones más recientes para muchas cosas, y estoy deseando que
lleguen
6

Stefano

He estado con Java desde el principio, por lo que desde mi punto de vista, la fama de ser lento fue creada por interfaces de interfaz gráfica de usuario (AWT, y luego Swing) sin respuesta y lentas, y en Applets probablemente debido a los tiempos de inicio lentos adicionales del VM.

Java ha estipulado y promovido una gran cantidad de investigaciones en el área de VM, y ha habido algunas mejoras, incluida la recolección de basura (en realidad, puede ajustar muchas cosas; sin embargo, a menudo veo sistemas donde solo se usan los valores predeterminados) y punto de acceso optimización (que al principio y probablemente aún es más eficiente en el lado del servidor).

Java en el backend y el nivel computacional no es tan lento. Colt es uno de los mejores ejemplos:

La última versión estable de Colt rompe la barrera de 1.9 Gflop / s en JDK ibm-1.4.1, RedHat 9.0, 2x [email protected] GHz.

Hay muchas cosas fuera de la corriente principal de Java que deben considerarse, como Java en tiempo real o mecanismos especiales para mejorar la velocidad como Javolution , así como la compilación anticipada (como gcj). Además, hay circuitos integrados que pueden ejecutar Java Bytecode directamente, como por ejemplo el que está en los iPhones y iPods actuales ARM Jazelle .

Creo que, en general, hoy es una decisión política (como no tener soporte para Java en el iPhone / iPod), y una decisión contra Java como lenguaje (porque muchos piensan que es demasiado detallado).

Sin embargo, hoy en día existen muchos otros lenguajes para Java VM (por ejemplo, Python, Ruby, JavaScript, Groovy, Scala, etc.) que pueden ser una alternativa.

Personalmente, sigo disfrutándolo como una plataforma flexible y confiable, con excelentes herramientas y disponibilidad de biblioteca, que permite trabajar con todo, desde el dispositivo más pequeño (por ejemplo, JavaCard) hasta los servidores más grandes.

Dieter
fuente
Ok, entonces otra mala reputación vino del kit de herramientas GUI. Por supuesto, supongo que, dado que las JVM modernas usan widgets nativos, se conectan a las bibliotecas del sistema operativo, ¿verdad? ¿o usan AWT / Swing para representar la misma apariencia de la plataforma host?
Stefano Borini
Stefano: Swing se basa realmente en la idea de la representación universal no nativa de widgets, por lo que su suposición es un poco incorrecta. De hecho, es un mecanismo de "apariencia y sensación enchufable" que permite a los componentes Swing emular la apariencia de los componentes nativos. Si está buscando algo así, puede consultar SWT ( eclipse.org/swt ), que de hecho se conectará al sistema operativo nativo y usará widgets nativos utilizando JNI (que se dice que es un cuello de botella).
Dieter
Java2D (utilizado para Swing) es muy rápido en estos días, y el uso de widgets nativos (SWT) no proporciona ningún beneficio de rendimiento. Al menos, eso es lo que leí cuando decidí si aprender Swing o SWT hace 6 meses.
Luigi Plinge
4

Un martillo es mucho más lento para extender la masa que muchas otras herramientas. No hace que el martillo sea "más lento", ni menos útil para las tareas para las que está diseñado.

Como lenguaje de programación general, Java está a la par con muchos (si no la mayoría) para una amplia gama de tareas de programación. Existen pruebas específicas y triviales para las que Java no superará a las soluciones codificadas a mano en lenguajes menos sofisticados, que están "más cerca del metal".

Pero cuando se trata de "aplicaciones del mundo real", Java a menudo es la herramienta adecuada. Ahora, dicho eso, nada detendrá a los desarrolladores de hacer una solución de bajo rendimiento utilizando CUALQUIER herramienta. El mal uso de la herramienta es un problema bien conocido (solo mire las reputaciones de PHP y VB). Sin embargo, el diseño y la sintaxis limpios de Java (en su mayoría) hacen mucho para reducir el mal uso.

mobiGeek
fuente
3

Java es un lenguaje de alto nivel y su reputación hoy en día es tener un rendimiento a la par con otros lenguajes de alto nivel comparables.

  1. Tiene semántica de enlace dinámico . En comparación con C ++, donde los métodos no virtuales se compilan como llamadas de función, incluso el mejor compilador de Java del mundo tiene que producir código que sea menos eficiente. Pero también es una semántica más limpia y de más alto nivel.

  2. No recuerdo los detalles, pero escuché en los primeros días de Java que había un mutex por objeto Java, que debía ser adquirido y liberado por cada método. Eso tiende a hacer que se adapte mejor a la concurrencia, aunque desafortunadamente solo un mutex por objeto no lo protegerá de razas o puntos muertos o cualquiera de las cosas malas que pueden suceder en los programas concurrentes. Esa parte, si es cierta, es un poco ingenua, pero proviene de buenas intenciones. Siéntase libre de completar los detalles si sabe más sobre este aspecto.

  3. Otra forma en que Java es un lenguaje de alto nivel es que Garbage-Collection . La recolección de basura puede ser más lenta que y para los programas que asignan a la vez toda la memoria que necesitan y funcionan con eso. El problema es que, en los idiomas que no tienen Garbage-Collection, ¡los programadores tienden a escribir solo que no sea gratis. También tienen gastos generales ... Además, no tener un GC obliga a especificar quién libera qué, y tener que especificar quién libera qué a su vez a veces lo obliga a hacer copias, cuando varias funciones van a necesitar los datos y no está claro qué lo usará en último lugar, mientras que la copia no hubiera sido necesaria en un lenguaje GC.mallocfree programas que asignan toda la memoria que necesitan a la vez y fallan si resulta que alguna constante arbitraria de tamaño máximo se ha desbordado. Entonces la comparación es manzanas con naranjas. Cuando los programadores hacen el esfuerzo de escribir y depurar programas con asignación dinámica de estructuras encadenadas en lenguajes que no son GC, a veces descubren que sus programas ya no son más rápidos que en un lenguaje GC, porquemalloc yfree

Pascal Cuoq
fuente
1. Probablemente no sea cierto con HotSpot. 2. Solo si marca el método como sincronizado.
Winston Ewert
1
1. El compilador no optimiza el código, pero la JVM es lo suficientemente inteligente como para determinar dinámicamente que solo se llaman uno o dos métodos virtuales y puede llamarlos de forma estática o incluso en línea. Estoy bastante seguro de que C ++ no puede incorporar métodos virtuales. 2. Cada objeto Java tiene un bloqueo. Tiene una pequeña sobrecarga (aproximadamente un byte) en cada objeto, pero tiene poco impacto si no se usa. 3. En Java puede asignar de una vez todos los objetos que necesita. Esto puede proporcionarle una aplicación que no tiene GC en todo el día. ;) El GC de Java es implícitamente multiproceso, algo que requiere bibliotecas especiales en C ++.
Peter Lawrey
C ++ puede hacer llamadas virtuales en línea, pero Java puede hacerlo en más casos, y también es más fuerte con la optimización de sitios de llamadas megamórficas.
Piotr Kołaczkowski
2

A mediados de los noventa, cuando Java llegó a la corriente principal, C ++ era el lenguaje dominante y la web todavía era bastante nueva. Además, JVM y GC eran conceptos relativamente nuevos en el desarrollo convencional. Las primeras JVM fueron un poco lentas (en comparación con C ++ que se ejecuta en metal desnudo) y también sufrieron pausas de recolección de basura a veces largas, lo que llevó a una reputación de Java lenta.

Ken Liu
fuente
¿Fue esto debido a la tecnología detrás del GC? Sé que tienen algunas estrategias (como capas generacionales para objetos) para ser más eficientes en la fase de GC. ¿Cuál era la estrategia en ese momento?
Stefano Borini el
1
IANA JVM experto, pero creo que en ese momento había un único algoritmo de marca / barrido roscado utilizado para GC, que requería que la JVM completa se detuviera mientras se realizaba el GC. Hoy en día hay marcas / barridos concurrentes y también hay muchas otras mejoras de rendimiento en la JVM.
Ken Liu el
2
Los algoritmos modernos de GC son buenos, pero creo que la mayor mejora fue JIT.
Pascal Thivent
1

Muchas aplicaciones de escritorio Java (en estos momentos: cosas como Eclipse) tienen una mala respuesta de la GUI, probablemente debido al alto consumo de memoria y al hecho de que el cargador de clases puede hacer mucho IO. Está mejorando, pero fue peor hace unos años.

A muchas (la mayoría) de las personas les gusta hacer generalizaciones, por lo que dicen "Java es lento" porque perciben que las aplicaciones son lentas cuando interactúan con ellas.

Wojciech Kaczmarek
fuente
¿Crees que el alto consumo de memoria proviene de la herramienta o de las bibliotecas de Java?
Stefano Borini
En el caso de Eclipse, desde la propia infraestructura de Eclipse. Lo mismo para las GUI "pesadas" en el pasado (JBuilder como lo recuerdo). Tengo la intuición de que es porque se necesitan muchos objetos repetitivos para usar una arquitectura de complemento (como Eclipse) en un lenguaje estáticamente tipado. Emacs también tiene complementos y su consumo de memoria es 10-20x menor que Eclipse cuando se realiza la codificación típica. El código Emacs Lisp se compila en bytecode y se carga en la instancia de emacs, luego se ejecuta, de forma similar al cargador de clases Java. Supongo que en Java hay toneladas de objetos intermedios instanciados para permitir cierta capacidad de conexión.
Wojciech Kaczmarek
1

El principal problema con las aplicaciones de Java es que es enorme debido al gran tamaño de la biblioteca de tiempo de ejecución de stock. Los programas enormes llenan mucho la memoria y tienden a intercambiarse, lo que significa que se vuelven lentos.

La razón por la que Sun JVM es grande es porque tiene un intérprete de código de bytes muy bueno que funciona manteniendo un registro de muchas cosas. Eso significa muchos datos, lo que significa memoria.

Es posible que desee ver la máquina virtual jamvm, que es un intérprete razonablemente rápido (sin código nativo) y muy pequeña. Incluso se inicia rápido.

Thorbjørn Ravn Andersen
fuente
1

Como dice Pascal, Java está a la par con otros lenguajes de alto nivel. Sin embargo, como alguien que trabajó con las JVM originales en Windows 98 , en ese momento el nivel de abstracción proporcionado por la máquina virtual Java era, digamos, doloroso.

Básicamente, fue la emulación de software con poca o ninguna optimización lo que damos por sentado hoy en la JVM.

caskey
fuente
0

La gente normalmente trota la línea "se interpreta". Porque alguna vez lo fue, y la mala prensa es transmitida por personas que dejaron Java como 'demasiado lento' y nunca volvieron a probar versiones más nuevas.

O tal vez "la gente es idiota" es una mejor respuesta.

Señor chico
fuente
0

Creo que algún día, tal vez no en un futuro demasiado cercano, los lenguajes compilados JIT superarán a los lenguajes compilados en cualquier aspecto (bueno, tal vez no el tiempo de inicio / consumo de memoria) debido al hecho de que los compiladores JIT pueden hacer un uso intensivo del tiempo de ejecución comportamiento y la plataforma en la que se están ejecutando.

método de ayuda
fuente
66
Creo que lo que quiere decir que decir es que (no se interpreta) código JIT-compilado venció código AOT. La interpretación siempre será más lenta que ejecutar código compilado. Por eso se utilizan los compiladores JIT. El problema: hay poca diferencia entre un compilador anticipado y un compilador JIT en términos de salida, excepto que un compilador JIT debe compilarse más rápidamente y puede usar información de tiempo de ejecución para insinuar sus optimizaciones. Los compiladores de AoT específicos de la plataforma con optimizaciones específicas de la plataforma casi siempre vencerán a JIT porque no hay límite de cuánto tiempo dedican a la optimización.
BobMcGee
Gracias por la respuesta, nunca pensé en el poco tiempo que los compiladores JIT tienen a su disposición.
método auxiliar
quieres decir, ¿algo así como la optimización adaptativa del punto de acceso?
Stefano Borini el
2
@BobMcGee: Muy bien. Se puede construir un programa C ++ para ejecutarse lentamente con comentarios de perfil para todas sus operaciones. Luego, el compilador es libre de reconstruir una versión muy rápida usando media hora de tiempo de CPU y 2 GB de RAM. Un JIT que hiciera esto haría que los usuarios se fueran.
Zan Lynx
1
El tiempo de compilación JIT es insignificante para aplicaciones de larga ejecución como servidores. AOT con PGO es más limitado en comparación con JIT por al menos 2 razones. Primero, la mayor diferencia de rendimiento se logra mediante optimizaciones ligeras. Compare gcc -O2 con gcc -O3. La mayoría de las veces no hay diferencia , a veces -O3 puede ser ligeramente mejor, a veces un poco peor, pero nunca experimenté una diferencia> 2x de esto. En segundo lugar, usando AOT incluso con PGO solo puede adivinar cuál será el perfil en el sitio de uso. Adivina mal, y estás muy por detrás del JIT. Y el perfil real puede ser extremadamente dependiente de la configuración.
Piotr Kołaczkowski