texto indicativo ejemplo java profiling performance

indicativo - Consejos de rendimiento de Java



placeholder java eclipse (14)

Tengo un programa que porté de C a Java. Ambas aplicaciones utilizan quicksort para ordenar algunos datos particionados (coordenadas genómicas).

La versión de Java se ejecuta rápidamente, pero me gustaría acercarla a la versión C. Estoy usando el Sun JDK v6u14.

Obviamente, no puedo lograr la paridad con la aplicación C, pero me gustaría saber qué puedo hacer para lograr el mayor rendimiento posible (dentro de los límites del entorno).

¿Qué tipo de cosas puedo hacer para probar el rendimiento de diferentes partes de la aplicación, el uso de la memoria, etc.? ¿Qué haría yo, específicamente?

Además, ¿qué trucos puedo implementar (en general) para cambiar las propiedades y la organización de mis clases y variables, reduciendo el uso de memoria y mejorando la velocidad?

EDITAR : Estoy usando Eclipse y obviamente preferiría las opciones gratuitas para las herramientas de terceros. ¡Gracias!


¿No puedes usar las funciones de clasificación que se incluyen en la biblioteca de Java?

Al menos, podría observar la diferencia de velocidad entre las dos funciones de clasificación.


¿Su código de clasificación se ejecuta solo una vez, por ejemplo, en una utilidad de línea de comandos que solo ordena, o varias veces, por ejemplo, una aplicación web que se ordena en respuesta a alguna entrada del usuario?

Lo más probable es que el rendimiento aumentaría significativamente después de que el código se haya ejecutado varias veces porque la máquina virtual HotSpot puede optimizar agresivamente si decide que su código es un punto de acceso.

Esta es una gran ventaja en comparación con C / C ++.

La máquina virtual, en tiempo de ejecución, optimiza el código que se usa a menudo, y lo hace bastante bien. El rendimiento puede en realidad ir más allá de C / C ++ debido a esto. De Verdad. ;)

Sin embargo, su Comparador personalizado podría ser un lugar para la optimización.

Trate de verificar primero las cosas de bajo costo (por ejemplo, la comparación int) antes de las cosas más caras (por ejemplo, la comparación de cadenas). No estoy seguro de si esos consejos se aplican porque no conozco su Comparador.

Utilice Collections.sort (lista, comparador) o Arrays.sort (matriz, comparador). La variante de matriz será un poco más rápida, consulte la documentación correspondiente.

Como dijo Andreas antes: no intente ser más astuto que la máquina virtual.


Desde el punto de vista metodológico, debe crear un perfil de la aplicación y luego tener una idea de qué componentes de su programa consumen mucho tiempo y mucha memoria: luego, observe detenidamente esos componentes para mejorar su rendimiento (consulte la ley de Amdahl ).

Desde un POV tecnológico puro, puedes usar algunos compiladores de código Java a código nativo, como el jet de Excelsior, pero debo tener en cuenta que las JVM recientes son realmente rápidas, por lo que la VM no debería impactar de manera significativa.


No optimices prematuramente.

Medir el rendimiento, luego optimizar.

Utilice las variables finales siempre que sea posible. No solo permitirá que JVM optimice más, sino que también hará que su código sea más fácil de leer y mantener.

Si haces tus objetos inmutables, no tienes que clonarlos.

Optimice cambiando el algoritmo primero, luego cambiando la implementación.

A veces es necesario recurrir a técnicas antiguas, como el desenrollado de bucle o el almacenamiento en caché de valores precalculados. Recuerda sobre ellos, incluso si no se ven bien, pueden ser útiles.


No trates de ser más astuto que el JVM.

en particular:

  • No intentes evitar la creación de objetos por el bien del rendimiento.

  • usar objetos inmutables donde sea aplicable.

  • use el alcance de sus objetos correctamente, para que el GC pueda hacer su trabajo.

  • use primitivas donde quiere decir primitivas (por ejemplo, int no anulables comparado con enteros anulables)

  • Utilizar los algoritmos y estructuras de datos incorporados.

  • al manejar la concurrencia use el paquete java.util.concurrent.

  • corrección sobre el rendimiento. Primero hazlo bien, luego mide, luego mide con un perfilador y luego optimiza.


Obviamente, perfil perfil perfil. Para Eclipse hay TPTP. Aquí hay un artículo sobre el complemento TPTP para Eclipse . Netbeans tiene su propio profiler . jvisualvm es agradable como una herramienta independiente. (El servidor dev.java.net completo parece estar inactivo en este momento, pero es un proyecto muy activo).

Lo primero que debe hacer es usar la rutina de clasificación de biblioteca, Collections.sort ; esto requerirá que sus objetos de datos sean Comparable . Esto podría ser lo suficientemente rápido y definitivamente proporcionará una buena línea de base.

Consejos generales:

  • Evite los bloqueos que no necesita (es posible que su JVM ya los haya optimizado)
  • Use StringBuilder (no StringBuffer debido a esa cosa de bloqueo que acabo de mencionar) en lugar de concatenar objetos String
  • Haz lo que puedas final ; Si es posible, haga sus clases completamente inmutables.
  • Si no está cambiando el valor de una variable en un bucle, intente levantarlo y ver si hace una diferencia (es posible que la JVM ya lo haya hecho por usted)
  • Intente trabajar en una ArrayList (o incluso en una matriz) para que la memoria a la que está accediendo sea contigua en lugar de potencialmente fragmentada como podría ser con una LinkedList
  • Quicksort puede ser paralelizado; Considera hacer eso (ver paralelización de quicksort )
  • Reduzca la visibilidad y el tiempo en vivo de sus datos tanto como sea posible (pero no contorsione su algoritmo para hacerlo a menos que el perfil muestre que es una gran ganancia)

Perfile y sintonice su programa java y la máquina host. La mayoría del código sigue la regla 80/20. Eso es el 20% del código, el 80% del tiempo, así que encuentre ese 20% y hágalo lo más rápido posible. Por ejemplo, el artículo Tuning Java Servers ( http://www.infoq.com/articles/Tuning-Java-Servers ) proporciona una descripción del desglose de la línea de comandos y luego aísla el problema usando herramientas como el registrador de vuelo Java, la memoria de Eclipse Analizador, y JProfiler.


Primera advertencia: asegúrese de haber realizado el perfilado o la evaluación comparativa adecuados antes de emprender cualquier trabajo de optimización. Los resultados a menudo lo iluminarán, y casi siempre le ahorrarán mucho esfuerzo desperdiciado en la optimización de algo que no importa.

Suponiendo que lo necesita, entonces puede obtener un rendimiento comparable al de C en Java, pero requiere un poco de esfuerzo. Necesita saber dónde está haciendo la "JVM" trabajo adicional y evitarlos.

En particular:

  • Evita la creación innecesaria de objetos . Si bien el montón de JVM y el GC son extremadamente rápidos y eficientes (probablemente el mejor del mundo, y casi seguro que es mejor que cualquier cosa que puedas rodar en C), sigue siendo una asignación del montón y eso será superado al evitar el montón en la primera lugar (pila o registro de asignación)
  • Evitar los primitivos en caja . Quieres usar double y no Double .
  • Utilice matrices primitivas para grandes trozos de datos. Las matrices primitivas de Java son básicamente tan rápidas como las matrices C / C ++ (tienen una verificación de límites adicionales, pero eso suele ser insignificante)
  • Evite todo lo que esté sincronizado : el subproceso de Java es bastante decente, pero sigue siendo una sobrecarga que puede que no necesite. Dale a cada hilo sus propios datos para trabajar.
  • Explotación de concurrencia : el soporte de concurrencia de Java es muy bueno. ¡Podrías usar todos tus núcleos! Este es un gran tema, pero hay muchos buenos libros / tutoriales disponibles.
  • Utilice clases de recopilación especializada para ciertos tipos de datos si tiene algunos requisitos muy específicos, por ejemplo, el soporte de algunos algoritmos de clasificación / búsqueda especializados. Es posible que necesite rodar el suyo propio, pero también hay algunas bibliotecas buenas con clases de colección de alto rendimiento disponibles que pueden ajustarse a sus necesidades; consulte, por ejemplo, Javoltion
  • Evite las grandes jerarquías de clase : este es un olor a diseño en el código de rendimiento. Cada capa de abstracción le está costando gastos generales. El código Java muy rápido a menudo terminará pareciéndose a C ...
  • Utilice métodos estáticos : el JIT puede optimizarlos extremadamente bien. Normalmente los alineará.
  • Utilice las clases concretas finales : una vez más, el JIT puede optimizarlas muy bien al evitar llamadas a funciones virtuales.
  • Genere su propio bytecode : si todo lo demás falla, esta puede ser una opción viable si desea obtener el máximo rendimiento absoluto de la JVM. Particularmente útil si necesitas compilar tu propio DSL. Use algo como ASM .

Quizás haya otras rutas para mejorar el rendimiento además de la micro-optimización del código. ¿Qué tal un algoritmo diferente para lograr lo que quieres que tu programa haga? ¿Puede ser una estructura de datos diferente?

O intercambie un poco de espacio de disco / RAM por velocidad, o si puede dedicar algo de tiempo por adelantado durante la carga de su programa, puede calcular previamente las tablas de búsqueda en lugar de hacer cálculos; de esa manera, el procesamiento es rápido. Es decir, hacer algunas concesiones de otros recursos disponibles.


Si su algoritmo tiene una gran cantidad de CPU, puede considerar aprovechar la paralelización. Es posible que pueda ordenar varios subprocesos y fusionar los resultados de nuevo más tarde.

Sin embargo, esto no es una decisión que deba tomarse a la ligera, ya que escribir código concurrente es difícil.


También intente ajustar los argumentos de tiempo de ejecución de la máquina virtual: la última versión de la máquina virtual, por ejemplo, incluye el siguiente indicador que puede mejorar el rendimiento en ciertos escenarios.

-XX:+DoEscapeAnalysis



jvisualvm se envía con JDK 6 ahora, esa es la razón por la que el enlace citado anteriormente no funciona. Simplemente escriba "jvisualvm <pid>", donde <pid> es el ID del proceso que desea rastrear. Verás cómo se usa el montón, pero no verás lo que lo está llenando.

Si es un proceso de larga ejecución, puede activar la opción -server cuando ejecute. Hay muchas opciones de ajuste disponibles para ti; eso es solo uno


Esto es lo que haría, en cualquier idioma. Si las muestras muestran que su rutina de comparación de clases está activa un gran porcentaje del tiempo, puede encontrar una manera de simplificarla. Pero tal vez el tiempo se va a otra parte. Diagnostica primero, para ver lo que está roto, antes de arreglar algo. Lo más probable es que si arreglas la cosa más grande, entonces otra cosa será la cosa más grande, y así sucesivamente, hasta que realmente hayas conseguido una aceleración bastante buena.