Sabemos que es costoso detectar excepciones. Pero, ¿también es costoso usar un bloque try-catch en Java incluso si nunca se lanza una excepción?
Encontré la pregunta / respuesta Stack Overflow ¿Por qué los bloques de prueba son caros? , pero es para .NET .
java
performance
try-catch
jsedano
fuente
fuente
try { /* do stuff */ } finally { /* make sure to release resources */ }
es legal y útilfinally
bloque usando untry-with-resources
Respuestas:
try
casi no tiene gastos en absoluto. En lugar de hacer el trabajo de configurar eltry
tiempo de ejecución, los metadatos del código se estructuran en el momento de la compilación de modo que cuando se produce una excepción, ahora se realiza una operación relativamente costosa de subir la pila y ver si hay algunotry
existen bloques que atrapen esto excepción. Desde la perspectiva de un laico, bientry
podría ser libre. En realidad, arrojar la excepción es lo que le cuesta, pero a menos que esté lanzando cientos o miles de excepciones, aún no notará el costo.try
tiene algunos costos menores asociados. Java no puede hacer algunas optimizaciones en el código en untry
bloque que de otro modo haría. Por ejemplo, Java a menudo reorganizará las instrucciones en un método para que se ejecute más rápido, pero Java también debe garantizar que si se produce una excepción, la ejecución del método se observa como si sus declaraciones, tal como están escritas en el código fuente, se ejecuten en orden hasta alguna línea.¡Porque en un
try
bloque se puede lanzar una excepción (en cualquier línea en el bloque de prueba! Algunas excepciones se lanzan de forma asincrónica, como llamarstop
a un Thread (que está en desuso), e incluso además, OutOfMemoryError puede suceder casi en cualquier lugar) y, sin embargo, puede detectarse y el código continúa ejecutándose después con el mismo método, es más difícil razonar sobre las optimizaciones que se pueden hacer, por lo que es menos probable que sucedan. (Alguien tendría que programar el compilador para que lo haga, razonar y garantizar la corrección, etc. Sería un gran dolor para algo destinado a ser 'excepcional') Pero una vez más, en la práctica no notará cosas como esta.fuente
try...finally
bloqueo sincatch
también impide algunas optimizaciones?Exception
objeto es lo que lleva la mayor parte del tiempo.Vamos a medirlo, ¿de acuerdo?
En mi computadora, esto imprime algo como:
Al menos en este ejemplo trivial, la declaración try no tuvo un impacto medible en el rendimiento. Siéntase libre de medir los más complejos.
En términos generales, recomiendo no preocuparse por el costo de rendimiento de las construcciones de lenguaje hasta que tenga evidencia de un problema de rendimiento real en su código. O como dijo Donald Knuth : "la optimización prematura es la raíz de todo mal".
fuente
-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
, tanto el bucle como la adición están presentes en el código nativo generado. Y no, los métodos abstractos no están en línea, porque su interlocutor no solo se compila a tiempo (presumiblemente, porque no se invoca suficientes veces).try
/catch
puede tener algún impacto en el rendimiento. Esto se debe a que evita que JVM haga algunas optimizaciones. Joshua Bloch, en "Java efectivo", dijo lo siguiente:fuente
Sí, como han dicho los demás, un
try
bloque inhibe algunas optimizaciones en los{}
personajes que lo rodean. En particular, el optimizador debe asumir que podría ocurrir una excepción en cualquier punto dentro del bloque, por lo que no hay garantía de que las declaraciones se ejecuten.Por ejemplo:
Sin el
try
, el valor calculado para asignar ax
podría guardarse como una "subexpresión común" y reutilizarse para asignar ay
. Pero debido a quetry
no hay garantía de que la primera expresión haya sido evaluada, entonces la expresión debe ser recalculada. Esto no suele ser un gran problema en el código de "línea recta", pero puede ser significativo en un bucle.Sin embargo, debe tenerse en cuenta que esto se aplica SOLO al código JITCed. javac solo realiza una pequeña cantidad de optimización, y el intérprete de bytecode tiene un costo cero para ingresar / salir de un
try
bloque. (No se generan bytecodes para marcar los límites del bloque).Y para bestsss:
Salida:
salida de javap:
No "GOTO".
fuente
catch/finally
marco.finally
bytecode, estry/catch(Throwable any){...; throw any;}
Y tiene una declaración catch con un marco y Throwable que DEBE SER definido (no nulo) y así sucesivamente. ¿Por qué intentas discutir sobre el tema, puedes verificar al menos algún bytecode? La directriz actual para impl. Finalmente, es copiar los bloques y evitar la sección goto (impl anterior) pero los bytecodes tienen que copiarse dependiendo de cuántos puntos de salida haya.Para comprender por qué no se pueden realizar las optimizaciones, es útil comprender los mecanismos subyacentes. El ejemplo más sucinto que pude encontrar se implementó en macros C en: http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html
Los compiladores a menudo tienen dificultades para determinar si un salto se puede localizar en X, Y y Z, por lo que omiten las optimizaciones que no pueden garantizar que sean seguras, pero la implementación en sí es bastante ligera.
fuente
Sin embargo, otro microbenchmark ( fuente ).
Creé una prueba en la que mido la versión del código try-catch y no-try-catch según un porcentaje de excepción. El 10% de porcentaje significa que el 10% de los casos de prueba tenían división por cero casos. En una situación es manejado por un bloque try-catch, en la otra por un operador condicional. Aquí está mi tabla de resultados:
Lo que dice que no hay una diferencia significativa entre ninguno de estos casos.
fuente
He encontrado la captura de NullPointException bastante costosa. Para las operaciones de 1.2k, el tiempo fue de 200ms y 12ms cuando lo manejé de la misma manera, lo
if(object==null)
que fue una mejora considerable para mí.fuente