Ich habe Code verglichen und konnte ihn nicht so schnell zum Laufen bringen wie mit java.math.BigInteger
, selbst wenn genau derselbe Algorithmus verwendet wurde. Also habe ich die java.math.BigInteger
Quelle in mein eigenes Paket kopiert und Folgendes versucht:
//import java.math.BigInteger;
public class MultiplyTest {
public static void main(String[] args) {
Random r = new Random(1);
long tm = 0, count = 0,result=0;
for (int i = 0; i < 400000; i++) {
int s1 = 400, s2 = 400;
BigInteger a = new BigInteger(s1 * 8, r), b = new BigInteger(s2 * 8, r);
long tm1 = System.nanoTime();
BigInteger c = a.multiply(b);
if (i > 100000) {
tm += System.nanoTime() - tm1;
count++;
}
result+=c.bitLength();
}
System.out.println((tm / count) + "nsec/mul");
System.out.println(result);
}
}
Wenn ich dies ausführe (jdk 1.8.0_144-b01 unter MacOS), wird Folgendes ausgegeben:
12089nsec/mul
2559044166
Wenn ich es mit der unkommentierten Importzeile ausführe:
4098nsec/mul
2559044166
Es ist fast dreimal so schnell, wenn Sie die JDK-Version von BigInteger verwenden, im Vergleich zu meiner Version, selbst wenn genau derselbe Code verwendet wird.
Ich habe den Bytecode mit Javap untersucht und die Compilerausgabe beim Ausführen mit Optionen verglichen:
-Xbatch -XX:-TieredCompilation -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions
-XX:+PrintInlining -XX:CICompilerCount=1
und beide Versionen scheinen den gleichen Code zu generieren. Verwendet der Hotspot also einige vorberechnete Optimierungen, die ich in meinem Code nicht verwenden kann? Ich habe immer verstanden, dass sie es nicht tun. Was erklärt diesen Unterschied?
quelle
Antworten:
Ja, HotSpot JVM ist eine Art "Betrug", da es eine spezielle Version einiger
BigInteger
Methoden gibt, die Sie im Java-Code nicht finden. Diese Methoden werden als JVM-Intrinsics bezeichnet .Insbesondere
BigInteger.multiplyToLen
ist eine instrumentelle Methode in HotSpot. Es gibt eine spezielle handcodierte Assembly-Implementierung in der JVM-Quellbasis, jedoch nur für die x86-64-Architektur.Sie können dieses Instrument mit der
-XX:-UseMultiplyToLenIntrinsic
Option deaktivieren , JVM zur Verwendung einer reinen Java-Implementierung zu zwingen. In diesem Fall entspricht die Leistung der Leistung Ihres kopierten Codes.PS Hier ist eine Liste anderer HotSpot-Methoden.
quelle
In Java 8 ist dies in der Tat eine intrinsische Methode. eine leicht modifizierte Version der Methode:
Führen Sie dies aus mit:
Dadurch werden viele Zeilen gedruckt, und eine davon ist:
In Java 9 hingegen scheint diese Methode nicht mehr intrinsisch zu sein, sondern ruft eine Methode auf, die intrinsisch ist:
Wenn Sie also denselben Code unter Java 9 (mit denselben Parametern) ausführen, wird Folgendes angezeigt:
Darunter befindet sich der gleiche Code für die Methode - nur eine etwas andere Benennung.
quelle