Ich habe die folgenden zwei Programme:
%Vor%und
%Vor% Hinweis: Der einzige Unterschied ist der Typ der Schleifenvariablen ( int
und long
).
Wenn ich das starte, druckt das erste Programm konsistent zwischen 0 und 16 ms, unabhängig vom Wert von N
. Der zweite dauert viel länger. Für N == Integer.MAX_VALUE
läuft es in ca. 1800 ms auf meinem Rechner. Die Laufzeit scheint in N
mehr oder weniger linear zu sein.
Also warum ist das?
Ich nehme an, der JIT-Compiler optimiert die int
Schleife zum Tod. Und das aus gutem Grund, denn offensichtlich tut es nichts. Aber warum nicht auch für die long
-Schleife?
Ein Kollege dachte, wir könnten den JIT-Compiler messen, der seine Arbeit in der long
-Schleife erledigt, aber da die Laufzeit in N
linear zu sein scheint, ist dies wahrscheinlich nicht der Fall.
Ich verwende JDK 1.6.0 Update 17:
%Vor%Ich bin auf der Windows XP Professional x64 Edition, Service Pack 2, mit einer Intel Core2 Quad-CPU mit 2,40 GHz.
DISCLAIMER
Ich weiß, dass Microbenchmarks in der Produktion nicht nützlich sind. Ich weiß auch, dass System.currentTimeMillis()
nicht so genau ist, wie sein Name vermuten lässt. Dies ist nur etwas, was mir beim Herumalbern aufgefallen ist, und ich war einfach neugierig, warum das passiert; nichts mehr.
Es ist eine interessante Frage, aber um ehrlich zu sein, bin ich nicht davon überzeugt, dass die Berücksichtigung von Hotspots Verhalten hier nützliche Informationen liefern wird. Alle Antworten, die Sie erhalten, sind in einem allgemeinen Fall nicht übertragbar (weil wir die Optimierungen betrachten, die Hotspot in einer bestimmten Situation durchführt), so dass sie Ihnen helfen zu verstehen, warum ein No-Op schneller ist als ein anderer. aber sie werden dir nicht helfen, schneller "echte" Programme zu schreiben .
Es ist auch unglaublich einfach, sehr irreführende Mikro-Benchmarks zu schreiben - siehe diese IBM DW-Artikel für einige der häufigsten Fallstricke, wie man sie vermeidet und einige allgemeine Kommentare zu dem, was du tust.
Also, das ist wirklich eine "no comment" Antwort, aber ich denke das ist die einzige gültige Antwort. Eine Kompilierungszeit-Trivial-No-Op-Schleife braucht nicht , um schnell zu sein, daher ist der Compiler in einigen dieser Bedingungen nicht so optimiert, dass er schnell ist.
Sie verwenden wahrscheinlich eine 32-Bit-JVM. Die Ergebnisse werden wahrscheinlich bei einer 64-Bit-JVM anders sein. In einer 32-Bit-JVM kann ein Int einer nativen 32-Bit-Ganzzahl zugeordnet und mit einer einzigen Operation inkrementiert werden. Dasselbe hält nicht lange, was mehr Operationen zum Inkrementieren erfordert.
Sehen Sie sich diese Frage für eine Diskussion über int und lange Größen an .
Meine Vermutung - und es ist nur eine Vermutung - ist das:
Die JVM kommt zu dem Schluss, dass die erste Schleife effektiv nichts tut, also entfernt sie diese vollständig. Keine Variable "entkommt" aus der for-Schleife.
Im zweiten Fall macht die Schleife auch nichts. Aber es könnte sein, dass der JVM-Code, der bestimmt, dass die Schleife nichts tut, eine "if (type of i) == int" -Klausel hat. In diesem Fall funktioniert die Optimierung zum Entfernen der do-nothing for-Schleife nur mit int.
Eine Optimierung, die Code entfernt, muss sicher sein, dass es keine Nebenwirkungen gibt. Die JVM-Programmierer scheinen sich auf der Seite der Vorsicht geirrt zu haben.
Ein solches Micro-Benchmarking ist nicht sehr sinnvoll, da die Ergebnisse stark von den internen Abläufen des Hotspot JIT abhängen.
Beachten Sie außerdem, dass die Systemuhrwerte, die Sie mit System.currentTimeMillis()
erhalten, keine Auflösung von 1 ms für alle Betriebssysteme haben. Sie können dies nicht verwenden, um Ereignisse sehr kurzer Dauer sehr genau zu messen.
Sehen Sie sich diesen Artikel an, der erklärt, warum Micro-Benchmarks in Java nicht so einfach sind, wie die meisten Leute denken: Anatomie eines fehlerhaften Mikrobenchmarks
Tags und Links java optimization performance jit