Es gibt eine Reihe von Konzepten, die auseinanderzuhalten sind:
- die Java-Programmiersprache selbst, die eine Textprogrammiersprache ist,
- das Java Virtual Machine-Bytecode- und Klassendateiformat , bei dem es sich um eine binär kompilierte Codierung des ursprünglichen Java-Quellcodes handelt, die als Austauschdateiformat zum Speichern, Laden und Freigeben von Java-Objektcode verwendet wird.
- Eine bestimmte Java Virtual Machine- Implementierung , die jedoch ein Interpreter sein kann, ist häufig eine JIT-basierte Implementierung.
- JIT hat Maschinencode generiert, der direkt auf dem Hardwareprozessor ausgeführt wird.
Java, die Programmiersprache , definiert keine Konzeptgröße primitiver Typen, da es (im Gegensatz zu C / C ++) keinen sizeof
Operator gibt: Größen können nicht über Sprachkonstrukte beobachtet werden, sodass die Sprache sie nicht definieren muss.
Wie @Ralf hervorhebt, definiert die Java-Sprache den Bereich der primitiven Typen, was für den Programmierer sehr relevant ist, da diese Bereiche über Konstrukte innerhalb der Sprache beobachtet werden können.
Die Sprache definiert eine Instrumentierungsfunktion, die die Untersuchung der Größe eines Objekts ermöglicht. (1) Dies erfordert jedoch eine Instrumentierung, (2) liefert nur eine Schätzung und (3) diese Anfrage gilt nicht für primitive Typen oder lokale Variablen.
Die JVM verwendet eine 32-Bit-Stapelzelle, in der lokale Variablen, Methodenargumente und Ausdruckswerte gespeichert sind. Grundelemente, die kleiner als 1 Zelle sind, werden ausgefüllt, Grundelemente, die größer als 32 Bit (lang und doppelt) sind, benötigen 2 Zellen
Das Auffüllzitat enthält Details zum Dateiformat der JVM-Klasse, das als Austauschmechanismus verwendet wird (im Unterschied zur Java-Sprache und einer JVM-Implementierung). Obwohl das, was es sagt, für die abstrakte Maschine und den JVM-Bytecode gilt, muss es nicht unbedingt für den JIT-Maschinencode gelten.
Das Auffüllungszitat beschränkt sich auch auf die Erörterung lokaler Variablen / Parameter / Ausdrücke, die normalerweise stapelweise zugewiesen werden (z. B. Auto oder Automatik in C / C ++), und behandelt keine Objekte / Arrays.
Die tatsächliche Größe solcher automatischer Variablen ist fast nie ein Problem (z. B. für die Leistung oder für den Speicherplatz).
Dies liegt zum Teil daran, dass die zugrunde liegenden Hardware-CPUs natürlicher mit größeren Bitgrößen (wie 32 oder 64) als mit 1-Bit arbeiten. Selbst 8- oder 16-Bit-Größen sind im Allgemeinen nicht schneller als 32, und manchmal erfordert die 8-Bit-Verarbeitung einen oder zwei zusätzliche Befehle, um mit den breiteren Registern des Hardware-Befehlssatzes zu arbeiten.
Ein weiterer Grund ist die eingeschränkte Verwendung lokaler Variablen - sie werden direkt vom Code und nur vom Code verwendet und unterliegen daher nicht wirklich Skalierungsproblemen - insbesondere im Vergleich zu Objekten und Arrays, die von Datenstrukturen potenziell beliebigen Maßstabs verwendet werden .
(Wir können Rekursion als Skalierung lokaler Variablen betrachten, sodass größere lokale Variablen in rekursiven Routinen den Stapelüberlauf früher riskieren.)
Die Größe von Objekten kann jedoch sehr wichtig sein, wenn die Anzahl der Instanzen hoch ist, und auch die Größe von Array-Elementen kann von Bedeutung sein, wenn die Anzahl der Elemente hoch ist.
Bedeutet dies, dass selbst Byte / Char / Short-Primitiva-Datentypen 32 Bit benötigen, obwohl ihre Größe als 8/16/16 Bit definiert ist?
Für Einheimische vielleicht, vielleicht nicht abhängig von der JIT.
Für Objekte innerhalb des JVM-Bytecode- und Klassendateimechanismus wird auf die Felder direkt durch ihre Identifizierung zugegriffen, und es wird keine Vorstellung von "Zellen" gegeben - wohingegen dies bei den (lokalen und Parameter-) Variablen der Fall ist.
Eine JVM-Implementierung (einschließlich ihrer JIT) hat die Flexibilität, die Feldreihenfolge innerhalb der Implementierung neu zu ordnen (z. B. auf Maschinencodeebene), sodass zwei 16-Bit-Felder dasselbe 32-Bit-Wort belegen können, selbst wenn sie nicht nebeneinander im Quellcode deklariert wurden ;; Dies reduziert den Overhead, der durch Polsterung verursacht wird, die erforderlich ist, um die Ausrichtung aufrechtzuerhalten. Solche Einstellungen, Auffüllungen und Feldplatzierungen sind auch sehr spezifisch für die Implementierung von JVM und nicht für das Format des JVM-Austauschformats. Theoretisch könnte die JIT Boolesche Werte in einem Array auf ein Bit reduzieren oder 8 einzelne Boolesche Felder in ein einzelnes Byte in einem Objekt packen. Das ist bei den meisten nicht die Wahl einer JVM-Implementierung.