Mir ist aufgefallen, dass ich immer int und double verwendet habe, egal wie klein oder groß die Zahl sein muss. Ist es in Java effizienter, byte
oder short
anstelle von int
und float
anstelle von zu verwenden double
?
Nehmen wir also an, ich habe ein Programm mit vielen Ints und Doubles. Wäre es wert, meine Ints in Bytes oder Shorts zu ändern, wenn ich wüsste, dass die Nummer passen würde?
Ich weiß, dass Java keine vorzeichenlosen Typen hat, aber kann ich noch etwas tun, wenn ich wüsste, dass die Zahl nur positiv ist?
Mit effizient meine ich meistens die Verarbeitung. Ich würde annehmen, dass der Garbage Collector viel schneller wäre, wenn alle Variablen halb so groß wären und dass die Berechnungen wahrscheinlich auch etwas schneller wären. (Ich denke, da ich an Android arbeite, muss ich mir auch etwas Sorgen um RAM machen)
(Ich würde annehmen, dass der Garbage Collector nur Objekte und keine Grundelemente behandelt, aber dennoch alle Grundelemente in verlassenen Objekten löscht, oder?)
Ich habe es mit einer kleinen Android-App versucht, aber ich habe überhaupt keinen Unterschied bemerkt. (Obwohl ich nichts "wissenschaftlich" gemessen habe.)
Bin ich falsch in der Annahme, dass es schneller und effizienter sein sollte? Ich würde es hassen, alles in einem riesigen Programm zu ändern, um herauszufinden, dass ich meine Zeit verschwendet habe.
Wäre es von Anfang an wert, wenn ich ein neues Projekt starte? (Ich meine, ich denke, jedes kleine bisschen würde helfen, aber wenn ja, warum scheint es nicht so, als ob es jemand tut.)
quelle
Dies hängt von der Implementierung der JVM sowie der zugrunde liegenden Hardware ab. Die meiste moderne Hardware ruft keine einzelnen Bytes aus dem Speicher (oder sogar aus dem Cache der ersten Ebene) ab, dh die Verwendung der kleineren primitiven Typen reduziert im Allgemeinen den Speicherbandbreitenverbrauch nicht. Ebenso haben moderne CPUs eine Wortgröße von 64 Bit. Sie können Operationen mit weniger Bits ausführen, aber das funktioniert, indem die zusätzlichen Bits verworfen werden, was auch nicht schneller ist.
Der einzige Vorteil besteht darin, dass kleinere primitive Typen zu einem kompakteren Speicherlayout führen können, insbesondere bei Verwendung von Arrays. Dies spart Speicherplatz, wodurch die Referenzlokalität verbessert werden kann (wodurch die Anzahl der Cache-Fehler verringert wird) und der Aufwand für die Speicherbereinigung verringert wird.
Im Allgemeinen ist die Verwendung der kleineren primitiven Typen jedoch nicht schneller.
Um dies zu demonstrieren, sehen Sie sich den folgenden Benchmark an:
welches auf meinem etwas alten Notizbuch gedruckt wird (Leerzeichen hinzufügen, um Spalten anzupassen):
Wie Sie sehen können, sind die Leistungsunterschiede recht gering. Die Optimierung von Algorithmen ist weitaus wichtiger als die Wahl des primitiven Typs.
quelle
short
und siebyte
sind effizienter, wenn sie in Arrays gespeichert werden, die groß genug sind, um eine Rolle zu spielen (je größer das Array,byte[2]
desto größer der Effizienzunterschied; a ist möglicherweise größer oder weniger effizient als einint[2]
, aber nicht genug, um eine Rolle zu spielen), aber dass einzelne Werte effizienter gespeichert werden alsint
.Die Verwendung von
byte
anstelle vonint
kann die Leistung steigern, wenn Sie sie in großer Menge verwenden. Hier ist ein Experiment:}}
Diese Klasse testet die Geschwindigkeit beim Erstellen eines neuen
TestClass
. Jeder Test macht es 20 Millionen Mal und es gibt 50 Tests.Hier ist die Testklasse:
Ich habe die
SpeedTest
Klasse geleitet und am Ende Folgendes bekommen:Jetzt ändere ich die Ints in der TestClass in Bytes und führe sie erneut aus. Hier ist das Ergebnis:
Ich glaube, dieses Experiment zeigt, dass die Verwendung von Byte anstelle von int die Effizienz steigern kann, wenn Sie eine große Anzahl von Variablen instanziieren
quelle
byte
dass >> langsamer << als sein könnteint
.Byte wird im Allgemeinen als 8 Bit betrachtet. kurz wird allgemein als 16 Bit angesehen.
In einer "reinen" Umgebung, die nicht Java ist, da die gesamte Implementierung von Bytes und Longs, Shorts und anderen lustigen Dingen im Allgemeinen vor Ihnen verborgen ist, nutzt Byte den Speicherplatz besser aus.
Ihr Computer ist jedoch wahrscheinlich nicht 8-Bit und wahrscheinlich nicht 16-Bit. Dies bedeutet, dass, um insbesondere 16 oder 8 Bits zu erhalten, auf "Tricks" zurückgegriffen werden muss, die Zeit verschwenden, um vorzutäuschen, dass es bei Bedarf auf diese Typen zugreifen kann.
Zu diesem Zeitpunkt hängt es davon ab, wie die Hardware implementiert ist. Wie ich jedoch gelernt habe, wird die beste Geschwindigkeit erreicht, wenn Dinge in Blöcken gespeichert werden, die für Ihre CPU bequem zu verwenden sind. Ein 64-Bit-Prozessor beschäftigt sich gerne mit 64-Bit-Elementen, und alles andere erfordert oft "technische Magie", um so zu tun, als würde er sich gerne mit ihnen befassen.
quelle
Einer der Gründe für die geringere Leistung von Short / Byte / Char ist der Mangel an direkter Unterstützung für diese Datentypen. Durch direkte Unterstützung bedeutet dies, dass in den JVM-Spezifikationen kein Befehlssatz für diese Datentypen erwähnt wird. Anweisungen wie Speichern, Laden, Hinzufügen usw. haben Versionen für den Datentyp int. Sie haben jedoch keine Versionen für short / byte / char. Betrachten Sie zB den folgenden Java-Code:
Gleiches wird wie unten in Maschinencode umgewandelt.
Erwägen Sie nun, int wie unten in short zu ändern.
Der entsprechende Maschinencode ändert sich wie folgt:
Wie Sie sehen können, wird zur Manipulation des kurzen Datentyps weiterhin die Anweisungsversion des Datentyps int verwendet und bei Bedarf explizit in den Datentyp int konvertiert. Aufgrund dessen wird die Leistung jetzt reduziert.
Als Grund für die Nichtunterstützung wird nun folgender Grund angeführt:
Zitiert aus der hier vorhandenen JVM-Spezifikation (Seite 58).
quelle
javac
Compiler nicht optimiert , und Sie können daraus keine verlässlichen Rückschlüsse auf die Leistung des Programms im wirklichen Leben ziehen. Der JIT-Compiler kompiliert diese Bytecodes zu tatsächlichen nativen Maschinenanweisungen und führt dabei einige ziemlich ernsthafte Optimierungen durch. Wenn Sie die Leistung des Codes analysieren möchten , müssen Sie die Anweisungen für den nativen Code überprüfen. (Und es ist kompliziert, weil Sie das Timing-Verhalten einer mehrstufigen x86_64-Pipeline berücksichtigen müssen.)Der Unterschied ist kaum spürbar! Es ist eher eine Frage des Designs, der Angemessenheit, der Einheitlichkeit, der Gewohnheit usw. Manchmal ist es nur eine Frage des Geschmacks. Wenn Sie sich nur darum kümmern, dass Ihr Programm in Betrieb genommen wird und das Ersetzen eines
float
durch ein Programm ersetzt,int
würde dies die Korrektheit nicht beeinträchtigen. Ich sehe keinen Vorteil darin, das eine oder andere zu wählen, es sei denn, Sie können nachweisen, dass die Verwendung eines der beiden Typen die Leistung verändert. Das Optimieren der Leistung basierend auf Typen, die sich in 2 oder 3 Bytes unterscheiden, ist wirklich das Letzte, was Sie beachten sollten. Donald Knuth hat einmal gesagt: "Vorzeitige Optimierung ist die Wurzel allen Übels" (nicht sicher, ob er es war, bearbeiten Sie, wenn Sie die Antwort haben).quelle
float
kann nicht alle ganzen Zahlen einerint
Dose darstellen. a kann auchint
keinen nicht ganzzahligen Wert darstellen, der diesfloat
kann. Das heißt, während alle int-Werte eine Teilmenge langer Werte sind, ist ein int keine Teilmenge eines float und ein float ist keine Teilmenge eines int.substituting a float for a double
, wenn ja, sollte der Antwortende die Antwort bearbeiten. Wenn nicht, sollte der Antwortende beschämt den Kopf hängen lassen und aus den von @pst genannten Gründen und aus vielen anderen Gründen zu den Grundlagen zurückkehren.