Speicherbelegung byte, short, int

hdi

Top Contributor
Hey,

Heute hat ein Kollege behauptet, dass byte short und int gleich viel Speicher belegen, da es theoretisch zwar einen Unterschied gibt, Java allerdings nur mit 4-Byte Chunks als kleinste Einheit umgehen kann. Das wär mir neu?! Ich hab jetzt ganz kurz über Runtime#free/maxMemory getestet mit einem int-Array und einem byte-Array, beide 1 Mio Slots.

das int-Array belegt 4.000.016 byte, das byte-Array 1.000.016 Million. Ist für mich auch logisch denn ein int belegt 4 byte und ein byte belegt.. nun ja 😉 Und die 16 kommen wohl vom Overhead des Arrays selbst. edit: Ja und short-Array belegt 2.000.016, passt also auch.

Bevor ich morgen zu dem hinrenn und ihn zur Sau mach wollte ich aber doch nochmal nachfragen. Immerhin ist das Testen der Speicherbelegung ja so ne Sache - man kann das jetzt nicht auf's byte genau nachvollziehen (Mach ich das Array 10 Mio Slots groß kommen die selben Werte heraus, bei 100 Mio Slots kommt sogar eine Negativ-Belegung raus, d.h. er hat mit dem Anlegen des Arrays sogar Speicher gewonnen.. :autsch🙂

Also wie is das nun. Ist da vllt doch etwas dran, und ich hab ihn nur falsch verstanden bzw er sich schlecht ausgedrückt, oder habt ihr davon auch zum ersten mal gehört? Hat da jemand detaillierte Lektüre? Ich kenne halt nur die typischen Tabellen wo ja eig. auch klar drinsteht dass die unterschiedlich viel Speicher belegen.

lg
 
Zuletzt bearbeitet:
Ja, solche Messungen über Runtime sind wirklich nicht sehr zuverlässig - ich frag' mich wo da diese hypergenauen 16 bytes herkommen - kam das wirklich rechnerisch genau so raus? Wäre fast Zufall, weil der Heap ja auch vergrößert werden kann (was auch den "magisch auftauchenden" Speicher erklären könnte).

Wie auch immer: Ein int[n]-array belegt 4 mal so viel Speicher wie ein byte[n]-Array. Das ist so, und notfalls kann man die Daten auch mal mit JNI zu C rüberziehen und mit GetPrimitiveArrayCritical schauen, was denn dort steht, wo dieser Zeiger hinzeigt: Einmal sind es 4-byte-ints, und einmal 1-byte-bytes.

Was dein Kollege vielleicht gemeint haben könte: Auf dem Stack (also dort, wo wirklich rumgerechnet wird, tief im Inneren der JVM) gibt es in bezug auf den "Speicher" keinen Unterschied: Auf dem Stack liegen immer 32bit, egal ob das nun bytes, shorts oder ints sind.
 
Ah okay, also das heißt:

lokale , primitive Variablen belegen immer mindestens 4 byte. (Du sagtest jetzt immer (genau) 4 byte, aber was ist mit long oder double?)

Aber alles andere, d.h. Objekte mitsamt deren Werten für Instanz-Variablen (und auch Klassen-Variablen??), belegen soviel Speicher wie es die typischen Tabellen anzeigen.

Hab ich das richtig verstanden?
 
Erstmal vorneweg: Objekte sind nochmal was ganz anderes - ich weiß aber nicht, welche "typischen Tabellen" du gerade meinst ???:L

Lokale primitive Variablen sind eigentlich nochmal was anderes, als der Stack, von dem ich geredet hatte - aber es gelten bei beiden etwa die gleichen Regeln:

Ein "Eintrag" des Stacks kann beliebige Datentypen aufnehmen. Ich hatte jetzt gesagt, dass das 32bit wäre, und die Frage nach long und double drängt sich auf, aber die belegen sozusagen (!) zwei "Einträge". Genaugenommen steht in der VM-Spec:
VM Spec The Structure of the Java Virtual Machine
3.6.2 Operand Stacks
...
Each entry on the operand stack can hold a value of any Java virtual machine type, including a value of type long or type double.
...
(Das klingt jetzt erstmal, als müßte ein "Eintrag" 64 bit haben, aber weiter unten steht...)
3.6.2 Operand Stacks
...
At any point in time an operand stack has an associated depth, where a value of type long or double contributes two units to the depth and a value of any other type contributes one unit.
...
Somit sind für ALLE Typen die Einträge 32 bit groß, und für long und double eben 2*32, auch wenn diese 2 "slots" dann trotzdem noch als "EIN (abstrakter) 'Eintrag'" bezeichnet werden.


Für lokale Variablen sieht's ähnlich aus:
VM Spec The Structure of the Java Virtual Machine
3.6.1 Local Variables
...
A single local variable can hold a value of type boolean, byte, char, short, int, float, reference, or returnAddress. A pair of local variables can hold a value of type long or double.

Also haben lokale Variablen auch 32 bit - und für long und double werden dann eben, wie beim Stack, 2*32 bit verwendet.
 
Also ich kenne den Stack nur als eben der Speicherbereich in dem lokale Variablen (mit ihren Werten) liegen. Von welchem Stack du jetzt redest ist mir nicht ganz klar.. Aber wie du schreibst ist das diesbezüglich ja das selbe. Und die Sache mit den Objekten hab ich erwähnt weil ich Stack im Zusammenhang mit Heap kenne, wobei eben gilt: Stack = lokale Variablen (für jeden Thread), Heap = Objekte (global für alle Threads zusammen)

PS: Mit typische Tabellen meinte ich die Auflistung der primitiven Typen mit ihrem Wertebereich und eben der Speicherbelegung:
Java Standard: Primitive Datentypen ? Wikibooks, Sammlung freier Lehr-, Sach- und Fachbücher
 
Hmja, aber die JVM selbst arbeitet ja mit einem Stack (grob wie auf Kellerautomat ? Wikipedia beschrieben - aber schon praktisch 😉 )

Sinngemäß-vereinfacht: Wenn im Code eine Rechnung steht wie
d = a+b+c
dann wird
- a auf den Stack gepusht
- b auf den Stack gepusht
- Die beiden oberen Stackelemente addiert und das Ergebnis auf den Stack gepusht
- c auf den Stack gepusht
- Die beiden oberen Stackelemente addiert und das Ergebnis auf den Stack gepusht
- Das obereste Element des Stacks ist dann a+b+c, also d

Der Stack dort ist nochmal was anderes als der Stack der z.B. die Parameter-Variablen bei Methodenaufrufen speichert.

Ehrlich gesagt weiß ich über die Oragnisation des Heaps nicht so viel (das ganze bisher hatte ich mir nur mal für die Implementierung eines Class-File-Readers reingezogen) aber man kann wohl sagen: Jede Variable belegt mindestens 32bit - außer wenn sie ein Array-Element ist.

Z.B. würde sowas wie
Java:
class SomeClass
{
    private byte b0;
    private byte b1;
...
    private byte b1000;
}
auf dem Heap 1000 * 4 byte (!) belegen, während
Java:
class SomeClass
{
    private byte b[] = new byte[1000];
}
1 Objektreferenz für den Array, aber dann nur noch 1000 * 1 byte (!) belegen würde.

Vielleicht meinte dein Kollege ersteres? :bahnhof:

Die Tabellen stimmen so natürlich, da geht es aber eher um die Frage, wie groß die Daten sind, die in solchen Variablen gespeichert werden können - weniger darum, wie viel Speicher sie wann wo wirklich belegen - außer natürlich, wenn man Arrays mit solchen Typen erstellt.
 
Achso also ist doch nur das Array ne Ausnahme? Das versteh ich nicht.. Ein Array ist doch quasi ein Objekt, also ein Wrapper über mehrere primtive Felder. Wenn ich ne Klasse X mit 10 Instanz-Variablen hab ist es doch eigentlich vom Aufbau das selbe?! Wieso belegt das dann mehr Speicher.. Und wie ist das zB bei ner List? Wenn ich dort 5 bytes reinadde, sind das dann 5 * 1 byte oder 5 * 4 byte?
 
Naja ein Array ist per se ja nur eine Adresse im Speicher, zu der werden dann eben i * x bytes hinzugezählt und so kommt man auf das jeweils i-te Element (x= Anzahl der bytes des Datentyps).
Wenn du einzelne Variablen hast, hast du auch auf jede Variable einen Zeiger drauf. Und, jetzt rate ich, es wäre auf Maschinencodeebene aufwendiger für sämtliche Variablen die byte länge mitzuspeichern, wenn man sie sowieso auf einen einheitlichen Stack packt. Bei arrays zahlt sich das allerdings aus, weil man da eine Menge gleicher Variablen hat, die praktischerweise noch hintereinander im Speicher stehen.
Bzgl List, da du in eine Collection ja sowieso nur Objekte reinpacken kannst, hast du wohl schon alleine durch ein Wrapper-Objekt mehr als 4 byte beisammen.
 
Zuletzt bearbeitet:
Achso also ist doch nur das Array ne Ausnahme? Das versteh ich nicht.. Ein Array ist doch quasi ein Objekt, also ein Wrapper über mehrere primtive Felder. Wenn ich ne Klasse X mit 10 Instanz-Variablen hab ist es doch eigentlich vom Aufbau das selbe?!

Hmnee... ein Array und eine "richtige" Klasse ist ja schon ein Unterschied. In einer Klassen können die Fields ja verschiedene Typen haben, und sie haben Namen - ein Array ist ganz dediziert nur ein "roher Speicherblock", bei dem man über einen Index einzelne Elemente ansprechen kann, die aber alle denselben Typ haben...
 

Zurück
Oben