Boolesche Größe in Java nicht definiert: Warum?

10

Ich sehe, dass die Größe des Booleschen Werts nicht definiert ist. Unten sind zwei Aussagen, die ich bei der Größe primitiver Java-Daten sehe

nicht genau definiert

Weitere Erklärung sagt

Boolescher Wert stellt eine Information dar, aber seine "Größe" ist nicht genau definiert.

Die Frage kam mir, warum Boolescher Wert in Java nicht mit 1 Bit dargestellt werden kann (oder 1 Byte, wenn Byte die minimale Darstellung ist).

Aber ich sehe, es wurde bereits bei beantwortet /programming/1907318/why-is-javas-boolean-primitive-size-not-defined wo es heißt

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

Bedeutet dies, dass selbst Byte / Char / Short-Primitiva-Datentypen 32 Bit benötigen, obwohl ihre Größe als 8/16/16 Bit definiert ist?

Können wir auch sagen, dass die boolesche Größe 32 Bit bei 32 Bit CPU und 64 Bit bei 64 Bit CPU beträgt?

user3222249
quelle
Does it mean even byte/char/short primitiva data types also take 32 bit though their size is defined as 8/16/16 bit ?-- Ja.
Robert Harvey
Also can we say boolean size will be 32 bit on 32 bit cpu and 64 bit on 64 bit cpu ?- Nein. Die Größe wird von der JVM festgelegt.
Robert Harvey
@RobertHarvey Wenn Datentypen für Byte / Zeichen / Kurzprimitive ebenfalls 32 Bit benötigen, wozu definiert man dann ihre Größe in Java als 8/16/16 Bit?
user3222249
Damit sie effizienter in Arrays gespeichert werden können.
Robert Harvey

Antworten:

11

TL; DR Das einzige, was sicher ist, ist, dass es booleanmindestens ein Bit belegt. Alles andere hängt von der JVM-Implementierung ab.

Die Java-Sprachspezifikation definiert keine Größen, sondern nur Wertebereiche (siehe Sprachspezifikation ). Es ist also nicht nur die booleanGröße, die auf dieser Ebene undefiniert ist. Und booleanhat zwei mögliche Werte: falseund true.

Die Virtual Machine Specification gibt an , dass booleanVariablen wie intmit den Werten 0 und 1 behandelt werden. Nur Arrays von booleanhaben spezifische Unterstützung. Auf der Ebene der virtuellen Maschine booleanbelegt eine Variable also den gleichen Speicherplatz wie eineint , dh eine Stapelzelle: mindestens 4 Byte, normalerweise 4 Byte bei 32-Bit-Java und 8 Byte bei 64-Bit.

Schließlich gibt es die HotSpot-Engine, die JVM-Bytecode in optimierten CPU-spezifischen Maschinencode kompiliert, und ich wette, dass sie in vielen Fällen den begrenzten Wertebereich eines int-masked booleanaus dem Kontext ableiten und eine kleinere Größe verwenden kann.

Ralf Kleberhoff
quelle
Wie Robert und Sie auch indirekt sagten: Wenn Byte / Zeichen / kurze primitive Datentypen ebenfalls 32 Bit benötigen, ist meine Frage, wozu ihre Größe in Java als 8/16/16 Bit definiert werden soll.
user3222249
Der Punkt beim Definieren ihres begrenzten Wertebereichs (oder "Größe", wenn Sie es vorziehen) ist ihre Semantik, z. B. das Umlaufen von 127 bis -128. Oft ist das unerwünscht, aber manchmal nützlich. Und dann gibt es Arrays der kürzeren Typen, und sie nehmen wirklich weniger Platz ein als int-Arrays. Und schließlich gibt es das Potenzial der JIT-Compiler / HotSpot-Engine, den Speicherplatz auf weniger als 4 Byte zu optimieren.
Ralf Kleberhoff
8

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 sizeofOperator 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.

Erik Eidt
quelle