2010-10-25 11 views
42

Hay una serie de consejos de rendimiento obsoletos por el compilador de Java y especialmente Profile-guided optimization. Por ejemplo, estas optimizaciones proporcionadas por la plataforma pueden reducir drásticamente (según las fuentes) el costo de las llamadas a funciones virtuales. VM también es capaz de alineación de métodos, desenrollado de bucles, etc.Obsolete Java Optimization Tips

¿Qué otras técnicas de optimización del rendimiento se aplicaron pero se han vuelto obsoletas por los mecanismos de optimización encontrados en las JVM más modernas?

+0

Tengo una recompensa sobre una pregunta relacionada aquí, si alguien tiene citas para las respuestas a esta: http://stackoverflow.com/questions/3963643/canonical-reference-on -jvm-internals-for-programmer-developers – andersoj

+0

Me cayó la pregunta es defectuoso porque depende del compilador que utiliza –

+0

No defectuoso, simplemente "amplio". –

Respuesta

23

El modificador final en métodos y parámetros de método no ayuda con el rendimiento en absoluto.

Además, el Java HotSpot wiki ofrece una buena visión general de las optimizaciones utilizadas por HotSpot y cómo utilizarlas de manera eficiente en código Java.

+2

buen enlace, pero no parece descartar 'final'. Dice que 'final' es una pista para subrayar. Pensé que había casos en los que el modificador final aseguraría al compilador que su valor no puede cambiar en un bucle, incluso si ese bucle invoca otros métodos y más allá del horizonte actual. – Will

+0

Ver: http://stackoverflow.com/questions/3961881/why-defining-class-as-final-improves-jvm-performance – andersoj

+4

'final' en métodos (o clases para el caso) no proporciona información al JIT. Sin embargo, 'final' en un parámetro de método podría proporcionar sugerencias de optimización útiles (similar a una variable local declarada como final). En última instancia, sin embargo, la razón para utilizar el final es forzar la inmutabilidad: esta es una característica de tiempo de diseño para hacer que el código sea más fácil de mantener. Cualquier beneficio de optimización tendría que ser: a) solo preocupado si realmente había un problema de rendimiento, yb) probado exhaustivamente para garantizar que realmente hiciera la diferencia. –

20

Personas reemplazando String a = "this" + var1 + " is " + var2; con múltiples llamadas a StringBuilder o StringBuffer. En realidad, ya usa StringBuilder detrás de escena.

+0

En este caso, yo cree que la optimización aún se aplica. El código de muestra que mostró construiría 3 instancias distintas de StringBuilder, una para cada concatenación; construir solo uno sería (un poco) más eficiente. Corrígeme si estoy equivocado. – RMorrisey

+3

Oh, pensé que haría el equivalente de 'String a = new StringBuilder (" this "). Append (var1) .append (" es "). Append (var2) .toString();'? –

+3

this * fuente no auténtica * http://www.rgagnon.com/javadetails/java-0129.html sugiere que Paul tiene razón respecto al único StringBuilder, pero dice que la capacidad predeterminada de StringBuilder puede ser demasiado corta (extraño, sería trivial que un compilador que se tomó el tiempo para usar un StringBuffer no se molestara en contar la capacidad antes del uso) – Will

8

En 2001 hice aplicaciones para un teléfono J2ME. Era del tamaño de un ladrillo. Y casi el poder computacional de un ladrillo.

Para que las aplicaciones Java se ejecuten de forma aceptable es necesario escribirlas de la manera más procesal posible. Además, la mejora de rendimiento muy grande fue capturar el ArrayIndexOutOfBoundsException para salir de bucles para todos los elementos en un vector. ¡Piénsalo!

Incluso en Android hay bucles "rápidos" a través de todos los elementos en una matriz y formas "lentas" de escribir lo mismo, como se menciona en los videos de Google IO en la parte interna de dalvik VM.

Sin embargo, en respuesta a su pregunta, diría que es muy inusual tener que micro-optimizar este tipo de cosas en estos días, y además esperaría que en una máquina virtual JIT (incluso el nuevo Android 2.2 VM, que agrega JIT) estas optimizaciones son discutibles. En 2001, el teléfono ejecutó el intérprete de KVM a 33MHz. Ahora ejecuta dalvik, una VM mucho más rápida que KVM, de 500MHz a 1500MHz, con una arquitectura ARM mucho más rápida (mejor procesador incluso permitiendo ganancias de velocidad de reloj) con L1 e.t.c. y JIT llega.

Todavía no nos encontramos en el ámbito en el que me sentiría cómodo realizando la manipulación directa de píxeles en Java, ya sea en el teléfono o en el escritorio con un i7, por lo que todavía hay código normal que Java no lo suficientemente rápido para. Here's an interesting blog que afirma que un experto ha dicho que Java tiene un 80% de velocidad C++ para algunas tareas pesadas de CPU; Soy escéptico, escribo código de manipulación de imágenes y veo un orden de magnitud entre Java y nativo para bucles sobre píxeles. Tal vez me estoy perdiendo un truco ...? : D

+1

Un poco de OT, pero en lo que respecta al rendimiento, un amigo mío ha creado un puerto Doom fiel a la fuente en Java, y obtiene alrededor de 130-145 FPS con una resolución de 640x480 en un solo P4 roscado a 3GHz. No OpenGL, solo blitting. –

+0

Sí, pero jugué aceptablemente a Doom en un 486 ... (sin embargo, el proyecto de tu amigo suena muy divertido y muy divertido) – Will

16

Es necesario definir las compensaciones de tiempo/memoria antes de comenzar la optimización del rendimiento. Así es como lo hago por mi memoria/aplicaciones críticas de tiempo (la repetición de algunas respuestas anteriormente, para ser completa):

  1. Regla # 1 Nunca hago la optimización del rendimiento en la etapa temprana de desarrollo. Nunca lo haga si no lo necesita realmente. Si decidió hacerlo, entonces:
  2. use el generador de perfiles para encontrar los cuellos de botella, revise el código fuente para encontrar las razones de los cuellos de botella;
  3. elija la estructura de datos apropiada con la mejor adaptación en las compensaciones de tiempo/memoria definidas;
  4. elegir los algoritmos apropiados (p.iteración vs recursión, etc.);
  5. evite el uso de objetos sincronizados de la biblioteca de Java, si realmente no lo necesita;
  6. evitar la creación de objetos explícita o implícitamente nueva;
  7. anula/vuelve a implementar los tipos de datos/algoritmos que vienen con java si y solo si estás seguro de que no se ajustan a tus requisitos.
  8. Utilice pruebas pequeñas e independientes para probar el rendimiento de las estructuras de datos/algos elegidas.
+2

Estos consejos no son realmente obselete. Es decir, es un consejo brillante, pero no estás respondiendo la pregunta. –

+2

-1: no responde lo que se está preguntando. –

1
  1. "La optimización prematura es la raíz de todo mal" (Donald Knuth)
  2. Es útil sólo para optimizar los cuellos de botella.
  3. Debe analizar el código en cada situación. Quizás pueda reemplazar el TreeSet por un HashSet rápido porque no necesita la función de clasificación o puede usar float en lugar de double (consulte el SDK de Android).
  4. Si ninguna técnica lo ayuda, puede intentar reescribir un fragmento de código y llamarlo a través del JNI, para que el código nativo funcione.
+6

-1 para la cita que es incompleta y tampoco relevante para la pregunta. Donald Knuth dijo: "Deberíamos olvidarnos de las pequeñas eficiencias, digamos el 97% del tiempo: la optimización prematura es la raíz de todo mal" En segundo lugar, la pregunta es acerca de las técnicas generales de optimización que ya no son aplicables, no hay nada que demuestre que es prematuro, es una discusión general – hhafez

4
  1. No llamar manualmente el recolector de basura, duele el rendimiento en las implementaciones de JVM modernas.
  2. Entero en lugar de Long no ahorrará mucho espacio, pero limitará el rango de los números.
  3. Evite las clases Enum generadas a mano y utilice el Enum incorporado. Java 1.5 introdujo Enums reales, úselos.
2

Al utilizar JVM de 64 bits con memoria RAM menos de 32 GB:

64 bits JVM utilización del 30% -50% más memoria en comparación a 32bit JVM debido a grandes punteros a objetos ordinarios. Puede reducir mucho este factor usando JDK6 +.

De JDK6u6p a JDK6u22 es opcional y se puede activar mediante la adición de argumento JVM:

-XX:+UseCompressedOops 

De JDK6u23 (JDK7 también) que está activada por defecto. Más información here.