Selbst wenn es nicht sein Hauptzweck ist, habe ich immer gedacht, dass das Schlüsselwort final
(in einigen Situationen und VM-Implementierungen) dem JIT helfen könnte.
Es könnte eine urbane Legende sein, aber ich habe mir nie vorgestellt, dass das Setzen eines Feldes final
die Leistungen negativ beeinflussen könnte.
Bis ich in einigen Code wie das lief:statisches endgültiges Feld, statisches Feld und Leistungen
private static final int THRESHOLD = 10_000_000;
private static int [] myArray = new int [THRESHOLD];
public static void main(String... args) {
final long begin = System.currentTimeMillis();
//Playing with myArray
int index1,index2;
for(index1 = THRESHOLD - 1; index1 > 1; index1--)
myArray[index1] = 42; //Array initial data
for(index1 = THRESHOLD - 1; index1 > 1; index1--) {
//Filling the array
for(index2 = index1 << 1; index2 < THRESHOLD; index2 += index1)
myArray[index2] += 32;
}
long result = 0;
for(index1 = THRESHOLD - 1; index1 > 1; index1-=100)
result += myArray[index1];
//Stop playing, let's see how long it took
System.out.println(result);
System.out.println((System.currentTimeMillis())-begin+"ms");
}
Lassen Sie uns einen Blick auf: private static int [] myArray = new int [THRESHOLD];
Unter W7 64-Bit und auf einer Basis von 10 aufeinanderfolgenden Durchläufen, ich die folgenden Ergebnisse:
THRESHOLD = 10^7
, 1.7.0u09 Client VM (Oracle):- läuft in ~ 2133ms, wenn
myArray
nicht endgültig ist. - läuft in ~ 2287ms wenn
myArray
ist endgültig. - Die-Server-VM erzeugt ähnliche Zahlen, d. H. 2131ms und 2284ms.
- läuft in ~ 2133ms, wenn
THRESHOLD = 3x10^7
, 1.7.0u09 Client VM (Oracle):- Läufe in 7647ms ~ wenn
myArray
nicht endgültig ist. - läuft in ~ 8190ms wenn
myArray
ist endgültig. - Die -server-VM produziert ~ 7653ms und ~ 8150ms.
- Läufe in 7647ms ~ wenn
THRESHOLD = 3x10^7
, 1.7.0u01 Client VM (Oracle):- Läufe in 8166ms ~ wenn
myArray
nicht endgültig ist. - läuft in ~ 9694ms wenn
myArray
ist endgültig. Das ist mehr als 15% Unterschied! - Der -server VM erzeugt einen vernachlässigbaren Unterschied zugunsten der nicht endgültigen Version, etwa 1%.
- Läufe in 8166ms ~ wenn
Bemerkung: Ich benutzte die javac des erzeugten Bytecode von JDK 1.7.0u09 für alle meine Tests. Der erzeugte Bytecode ist für beide Versionen genau gleich, mit Ausnahme der myArray
Deklaration, die erwartet wurde.
Warum ist die Version mit static final myArray
langsamer als die mit static myArray
?
EDIT (Aubin Version meiner Schnipsel verwenden):
Es scheint, dass die Unterschiede zwischen der Version mit final
Schlüsselwort und den man ohne nur in der ersten Iteration liegt. Irgendwie ist die Version mit final
immer langsamer als sein Gegenstück ohne auf der ersten Iteration, dann haben die nächsten Iterationen ähnliche Zeiten.
Zum Beispiel, mit THRESHOLD = 10^8
und läuft mit 1.7.0u09 Client die erste Berechnung dauert ca. 35s, während die zweite 'nur' 30s dauert.
Offensichtlich führte die VM eine Optimierung durch, war das JIT in Aktion und warum trat es nicht früher (zum Beispiel durch Kompilieren der zweiten Ebene der verschachtelten Schleife, dieser Teil war der Hotspot)?
Beachten Sie, dass meine Bemerkungen mit 1.7.0u01 Client-VM noch gültig sind. Mit dieser Version (und möglicherweise früheren Versionen), läuft der Code mit final myArray
langsamer als der ohne dieses Schlüsselwort: 2671ms vs 2331ms auf einer Basis von 200 Iterationen.
Nur 2 Sekunden Laufzeit? Ich glaube nicht, dass das JIT dort wirklich ernsthafte Optimierungen vorgenommen hat. –
10 Läufe sind nicht genug, 1000 wird besser, und der erste Lauf kann nicht berücksichtigt werden – Aubin
@Aubin Es wird eine Weile dauern, ich werde den Beitrag aktualisieren, wenn es vorbei sein wird. – Jerome