Wir wissen, dass es teuer ist, Ausnahmen zu erwischen. Aber ist es auch teuer, einen Try-Catch-Block in Java zu verwenden, selbst wenn niemals eine Ausnahme ausgelöst wird?
Ich habe die Frage / Antwort zum Stapelüberlauf gefunden. Warum sind Versuchsblöcke teuer? , aber es ist für .NET .
java
performance
try-catch
jsedano
quelle
quelle
try { /* do stuff */ } finally { /* make sure to release resources */ }
ist legal und nützlichfinally
Block sogar mit einemtry-with-resources
Antworten:
try
hat fast keine Kosten. Anstatt die Arbeit zur Einrichtung destry
zur Laufzeit zu erledigen, sind die Metadaten des Codes zur Kompilierungszeit so strukturiert, dass beim Auslösen einer Ausnahme jetzt eine relativ teure Operation ausgeführt wird, bei der der Stapel hochgefahren wird und geprüft wird, obtry
Blöcke vorhanden sind, die dies abfangen würden Ausnahme.try
Kann aus der Sicht eines Laien genauso gut frei sein. Es wird tatsächlich die Ausnahme ausgelöst, die Sie kostet - aber wenn Sie nicht Hunderte oder Tausende von Ausnahmen auslösen, werden Sie die Kosten immer noch nicht bemerken.try
hat einige kleinere Kosten damit verbunden. Java kann einige Optimierungen für Code in einemtry
Block nicht vornehmen, die es sonst tun würde. Beispielsweise ordnet Java Anweisungen in einer Methode häufig neu an, damit sie schneller ausgeführt wird. Java muss jedoch auch sicherstellen, dass beim Auslösen einer Ausnahme die Ausführung der Methode so beobachtet wird, als würden ihre im Quellcode geschriebenen Anweisungen ausgeführt um bis zu einer Zeile.Denn in einem
try
Block kann eine Ausnahme ausgelöst werden (in jeder Zeile des try-Blocks! Einige Ausnahmen werden asynchron ausgelöst, z. B. durch Aufrufenstop
eines Threads (der veraltet ist), und sogar darüber hinaus kann OutOfMemoryError fast überall auftreten) kann abgefangen werden und Code wird anschließend auf dieselbe Weise weiter ausgeführt. Es ist schwieriger, über Optimierungen nachzudenken, die vorgenommen werden können, sodass die Wahrscheinlichkeit geringer ist, dass sie auftreten. (Jemand müsste den Compiler programmieren, um dies zu tun, die Richtigkeit zu begründen und zu garantieren usw. Es wäre ein großer Schmerz für etwas, das "außergewöhnlich" sein soll.) Aber auch in der Praxis werden Sie solche Dinge nicht bemerken.quelle
try...finally
Block ohnecatch
auch einige Optimierungen?Exception
Objekts dauert die meiste Zeit.Lassen Sie es uns messen, sollen wir?
Auf meinem Computer wird Folgendes gedruckt:
Zumindest in diesem trivialen Beispiel hatte die try-Anweisung keinen messbaren Einfluss auf die Leistung. Fühlen Sie sich frei, komplexere zu messen.
Im Allgemeinen empfehle ich, sich keine Gedanken über die Leistungskosten von Sprachkonstrukten zu machen, bis Sie Hinweise auf ein tatsächliches Leistungsproblem in Ihrem Code haben. Oder wie Donald Knuth es ausdrückte : "Vorzeitige Optimierung ist die Wurzel allen Übels".
quelle
-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
sowohl die Schleife als auch die Addition darin im generierten nativen Code vorhanden. Und nein, die abstrakten Methoden sind nicht inline, weil ihr Aufrufer nicht nur rechtzeitig kompiliert wird (vermutlich, weil er nicht oft genug aufgerufen wird).try
Ichcatch
kann einen Einfluss auf die Leistung haben. Dies liegt daran, dass JVM dadurch keine Optimierungen vornehmen kann. Joshua Bloch sagte in "Effective Java" Folgendes:quelle
Ja, wie die anderen gesagt haben, verhindert ein
try
Block einige Optimierungen in den ihn{}
umgebenden Zeichen. Insbesondere muss der Optimierer davon ausgehen, dass an jedem Punkt innerhalb des Blocks eine Ausnahme auftreten kann, sodass nicht garantiert werden kann, dass Anweisungen ausgeführt werden.Beispielsweise:
Ohne das könnte
try
der Wert, dem die Zuweisung berechnet wurde,x
als "allgemeiner Unterausdruck" gespeichert und zur Zuweisung wiederverwendet werdeny
. Aufgrund dertry
Tatsache, dass es keine Garantie dafür gibt, dass der erste Ausdruck jemals ausgewertet wurde, muss der Ausdruck neu berechnet werden. Dies ist normalerweise keine große Sache im "geradlinigen" Code, kann aber in einer Schleife von Bedeutung sein.Es ist jedoch zu beachten, dass dies NUR für JITCed-Code gilt. javac führt nur eine geringfügige Optimierung durch, und der Bytecode-Interpreter hat keine Kosten für das Betreten / Verlassen eines
try
Blocks. (Es werden keine Bytecodes generiert, um die Blockgrenzen zu markieren.)Und für Bests:
Ausgabe:
Javap-Ausgabe:
Kein "GOTO".
quelle
catch/finally
Frame fällt .finally
Bytecode, es isttry/catch(Throwable any){...; throw any;}
Und es hat eine catch-Anweisung mit einem Frame und Throwable, die definiert werden muss (nicht null) und so weiter. Warum versuchen Sie, über das Thema zu streiten, können Sie zumindest einen Bytecode überprüfen? Die aktuelle Richtlinie für impl. von schließlich werden die Blöcke kopiert und der Abschnitt goto vermieden (vorheriges impl), aber die Bytecodes müssen kopiert werden, abhängig davon, wie viele Austrittspunkte es gibt.Um zu verstehen, warum die Optimierungen nicht durchgeführt werden können, ist es hilfreich, die zugrunde liegenden Mechanismen zu verstehen. Das prägnanteste Beispiel, das ich finden konnte, wurde in C-Makros unter folgender Adresse implementiert: http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html
Compiler haben häufig Schwierigkeiten zu bestimmen, ob ein Sprung auf X, Y und Z lokalisiert werden kann, sodass sie Optimierungen überspringen, die sie nicht als sicher garantieren können, aber die Implementierung selbst ist eher leicht.
quelle
Noch ein Mikrobenchmark ( Quelle ).
Ich habe einen Test erstellt, in dem ich die Codeversion try-catch und no-try-catch anhand eines Ausnahmeprozentsatzes messe. 10% Prozent bedeutet, dass 10% der Testfälle durch Null geteilt wurden. In einer Situation wird es von einem Try-Catch-Block behandelt, in der anderen von einem bedingten Operator. Hier ist meine Ergebnistabelle:
Was besagt, dass es keinen signifikanten Unterschied zwischen diesen Fällen gibt.
quelle
Ich fand es ziemlich teuer, NullPointException zu fangen. Für 1,2-km-Operationen betrug die Zeit 200 ms und 12 ms, als ich sie auf die gleiche Weise handhabte,
if(object==null)
was für mich eine ziemlich gute Verbesserung war.quelle