¿Existe algún beneficio en el rendimiento de una forma u otra? ¿Es específico del compilador / VM? Estoy usando Hotspot.
java
performance
premature-optimization
Andy Faibishenko
fuente
fuente
Cuatro años después...
Bien, con la esperanza de resolver esta pregunta de una vez y para siempre, he escrito un punto de referencia que muestra cómo los diferentes tipos de llamadas (virtuales, no virtuales, estáticas) se comparan entre sí.
Lo ejecuté en ideone , y esto es lo que obtuve:
(Es mejor un número mayor de iteraciones).
Como se esperaba, las llamadas a métodos virtuales son las más lentas, las llamadas a métodos no virtuales son más rápidas y las llamadas a métodos estáticos son incluso más rápidas.
Lo que no esperaba era que las diferencias fueran tan pronunciadas: las llamadas a métodos virtuales se midieron para que se ejecutaran a menos de la mitad de la velocidad de las llamadas a métodos no virtuales, que a su vez se midieron para que se ejecutaran un 15% más lento que las llamadas estáticas. Eso es lo que muestran estas medidas; de hecho, las diferencias reales deben ser un poco más pronunciadas, ya que para cada llamada de método virtual, no virtual y estático, mi código de evaluación comparativa tiene una sobrecarga constante adicional de incrementar una variable entera, verificar una variable booleana y realizar un bucle si no es cierto.
Supongo que los resultados variarán de una CPU a otra y de JVM a JVM, así que pruébelo y vea lo que obtiene:
Vale la pena señalar que esta diferencia de rendimiento solo es aplicable al código que no hace nada más que invocar métodos sin parámetros. Cualquier otro código que tenga entre las invocaciones diluirá las diferencias, y esto incluye el paso de parámetros. En realidad, la diferencia del 15% entre las llamadas estáticas y no virtuales probablemente se explique en su totalidad por el hecho de que el
this
puntero no tiene que pasarse al método estático. Por lo tanto, solo se necesitaría una cantidad bastante pequeña de código haciendo cosas triviales entre llamadas para que la diferencia entre los diferentes tipos de llamadas se diluya hasta el punto de no tener ningún impacto neto.Además, las llamadas a métodos virtuales existen por una razón; tienen un propósito que cumplir y se implementan utilizando los medios más eficientes proporcionados por el hardware subyacente. (El conjunto de instrucciones de la CPU). Si, en su deseo de eliminarlos reemplazándolos con llamadas no virtuales o estáticas, termina teniendo que agregar hasta un ápice de código adicional para emular su funcionalidad, entonces la sobrecarga neta resultante está limitada para ser no menos, sino más. Posiblemente, mucho, mucho, insondablemente mucho, más.
fuente
VirtualTest | 488846733 -- NonVirtualTest | 480530022 -- StaticTest | 484353198
en mi instalación de OpenJDK. FTR: Eso es incluso cierto si elimino elfinal
modificador. Por cierto. Tuve que hacer elterminate
campovolatile
, de lo contrario la prueba no terminó.VirtualTest | 12451872 -- NonVirtualTest | 12089542 -- StaticTest | 8181170
. No solo que OpenJDK en mi portátil logra realizar 40 veces más iteraciones, la prueba estática siempre tiene aproximadamente un 30% menos de rendimiento. Este podría ser un fenómeno específico de ART, porque obtengo un resultado esperado en una tableta con Android 4.4:VirtualTest | 138183740 -- NonVirtualTest | 142268636 -- StaticTest | 161388933
Bueno, las llamadas estáticas no se pueden anular (por lo que siempre son candidatas para la inserción) y no requieren ninguna verificación de nulidad. HotSpot realiza un montón de optimizaciones interesantes, por ejemplo, métodos que pueden negar estas ventajas, pero son posibles razones por las que una llamada estática puede ser más rápida.
Sin embargo, eso no debería afectar su diseño, el código de la manera más legible y natural, y solo debe preocuparse por este tipo de microoptimización si tiene una causa justa (lo que casi nunca lo hará).
fuente
Es específico del compilador / VM.
Por lo tanto, probablemente no valga la pena preocuparse por ello a menos que haya identificado esto como un problema de rendimiento verdaderamente crítico en su aplicación. La optimización prematura es la raíz de todos los males, etc.
Sin embargo, he visto que esta optimización proporciona un aumento sustancial del rendimiento en la siguiente situación:
Si lo anterior se aplica a usted, puede valer la pena probarlo.
También hay otra buena razón (¡y potencialmente incluso más importante!) Para usar un método estático: si el método realmente tiene semántica estática (es decir, lógicamente no está conectado a una instancia determinada de la clase), entonces tiene sentido hacerlo estático para reflejar este hecho. Los programadores experimentados de Java notarán entonces el modificador estático e inmediatamente pensarán "¡ajá! Este método es estático por lo que no necesita una instancia y presumiblemente no manipula el estado específico de la instancia". Entonces habrá comunicado la naturaleza estática del método de manera efectiva ...
fuente
Como han dicho los carteles anteriores: Esto parece una optimización prematura.
Sin embargo, hay una diferencia (una parte del hecho de que las invocaciones no estáticas requieren un empuje adicional de un objeto llamado en la pila de operandos):
Dado que los métodos estáticos no se pueden anular, no habrá búsquedas virtuales en tiempo de ejecución para una llamada de método estático. Esto puede resultar en una diferencia observable en algunas circunstancias.
La diferencia a nivel de código de bytes es que una llamada a un método no estático se realiza a través de
INVOKEVIRTUAL
,INVOKEINTERFACE
oINVOKESPECIAL
mientras se realiza una llamada a un método estáticoINVOKESTATIC
.fuente
invokespecial
ya que no es virtual.Es increíblemente poco probable que cualquier diferencia en el rendimiento de las llamadas estáticas frente a las no estáticas esté marcando una diferencia en su aplicación. Recuerde que "la optimización prematura es la raíz de todos los males".
fuente
7 años después ...
No tengo un gran grado de confianza en los resultados que encontró Mike Nakis porque no abordan algunos problemas comunes relacionados con las optimizaciones de Hotspot. Instrumenté los puntos de referencia usando JMH y encontré que la sobrecarga de un método de instancia es de aproximadamente 0.75% en mi máquina frente a una llamada estática. Dada esa baja sobrecarga, creo que, excepto en las operaciones más sensibles a la latencia, podría decirse que no es la mayor preocupación en el diseño de una aplicación. Los resultados resumidos de mi punto de referencia JMH son los siguientes;
Puedes ver el código aquí en Github;
https://github.com/nfisher/svsi
El punto de referencia en sí es bastante simple, pero tiene como objetivo minimizar la eliminación de código muerto y el plegado constante. Es posible que haya otras optimizaciones que he pasado por alto / pasado por alto y es probable que estos resultados varíen según la versión de JVM y el sistema operativo.
fuente
ops/s
principalmente en un entorno ART (por ejemplo, uso de memoria, tamaño de archivo .oat reducido, etc.). ¿Conoce alguna herramienta o forma relativamente simple en la que se pueda intentar comparar estas otras métricas?Para la decisión de si un método debe ser estático, el aspecto de rendimiento debe ser irrelevante. Si tiene un problema de rendimiento, hacer que muchos métodos sean estáticos no le salvará el día. Dicho esto, es casi seguro que los métodos estáticos no son más lentos que cualquier método de instancia, en la mayoría de los casos ligeramente más rápidos :
1.) Los métodos estáticos no son polimórficos, por lo que la JVM tiene menos decisiones que tomar para encontrar el código real para ejecutar. Este es un punto discutible en Age of Hotspot, ya que Hotspot optimizará las llamadas al método de instancia que tienen solo un sitio de implementación, por lo que realizarán lo mismo.
2.) Otra sutil diferencia es que los métodos estáticos obviamente no tienen ninguna referencia a "esto". Esto da como resultado un marco de pila una ranura más pequeño que el de un método de instancia con la misma firma y cuerpo ("esto" se coloca en la ranura 0 de las variables locales en el nivel de código de bytes, mientras que para los métodos estáticos se usa la ranura 0 para la primera parámetro del método).
fuente
Puede haber una diferencia, y puede ir en cualquier dirección para cualquier fragmento de código en particular, y puede cambiar incluso con una versión menor de la JVM.
Definitivamente, esto es parte del 97% de pequeñas eficiencias que debe olvidarse .
fuente
TableView
de millones de registros.En teoría, menos costoso.
La inicialización estática se realizará incluso si crea una instancia del objeto, mientras que los métodos estáticos no realizarán ninguna inicialización que se realiza normalmente en un constructor.
Sin embargo, no lo he probado.
fuente
Como señala Jon, los métodos estáticos no se pueden anular, por lo que simplemente invocar un método estático puede ser, en un tiempo de ejecución de Java suficientemente ingenuo, más rápido que invocar un método de instancia.
Pero luego, incluso asumiendo que está en el punto en el que le importa estropear su diseño para ahorrar unos pocos nanosegundos, eso solo trae otra pregunta: ¿necesitará que el método se anule a sí mismo? Si cambia su código para convertir un método de instancia en un método estático para ahorrar un nanosegundo aquí y allá, y luego da la vuelta e implementa su propio despachador además de eso, es casi seguro que el suyo será menos eficiente que el construido en su tiempo de ejecución de Java ya.
fuente
Me gustaría agregar a las otras excelentes respuestas aquí que también depende de su flujo, por ejemplo:
Preste atención a que crea un nuevo objeto MyRowMapper por cada llamada.
En su lugar, sugiero usar aquí un campo estático.
fuente