Speicherverwaltung

Hallo liebe Leute,

anbei eine ganz allgemeine Frage zu Speicherverwaltung:

Ich habe ein großes Programm in dem ich eine Menge Daten in vielen Objekten speichere, wodurch ich zu dem Schluss gekommen bin Integer, Boolean, Double usw. statt primitive Datentypen zu nehmen. Jetzt habe ich mir Gedanken über die Speicherverwaltung gemacht und folgendes Beispiel ausgepackt:

Java:
                System.out.println("Integer: ");
		Integer a5 = 2;
		Integer b5 = new Integer(2);
		Integer c5 = 2;
		System.out.println(System.identityHashCode(a5)); // 544359254
		System.out.println(System.identityHashCode(b5)); // 765645758
		System.out.println(System.identityHashCode(c5)); // 544359254
		System.out.println(a5 == b5); // false
		System.out.println(a5 == c5); // true
		
		System.out.println("Boolean: ");
		Boolean a6 = true;
		Boolean b6 = new Boolean(true);
		Boolean c6 = true;
		System.out.println(System.identityHashCode(a6)); // 486241882
		System.out.println(System.identityHashCode(b6)); // 1092033939
		System.out.println(System.identityHashCode(c6)); // 486241882
		System.out.println(a6 == b6); // false
		System.out.println(a6 == c6); // true

Mein Fazit daraus war, dass es so ähnlich wie bei String und String Interning ist und man grundsätzlich auf new verzichten sollte, um Speicherplatz zu sparen. Dann habe ich das Gleiche allerdings mit Double probiert:

Java:
                System.out.println("Double: ");
		Double a1 = 1.0;
		Double b1 = new Double(1.0);
		Double c1 = 1.0;
		Double d1 = a1;
		System.out.println(System.identityHashCode(a1)); // 402081892
		System.out.println(System.identityHashCode(b1)); // 1806805382
		System.out.println(System.identityHashCode(c1)); // 1559286694
		System.out.println(System.identityHashCode(d1)); // 402081892
		System.out.println(a1 == b1); // false
		System.out.println(a1 == c1); // false
		System.out.println(a1 == d1); // true

Joar, das war dann natürlich enttäuschend, weil das Double a1 und c1 an unterschiedlichen Stellen gespeichert wird und damit heap verschwendet wird (es sei denn ich setze es explizit gleich). Die JVM-Maschine erkennt die Gleichheit also nicht. Dementsprechend ist es doch eigentlich wurst ob ich bei Double ein new hinsetze oder nicht?

Stimmen meine Überlegungen soweit?

Danke

Grüße
PanchoVarallo
 

Natac

Bekanntes Mitglied
Beim wrappen von primitiven Typen würde grundsätzlich von new abraten und auf <Wrapper>.valueOf setzen. Da ist teilweise schon ein Cache-Management hinter (Integer -128 bis 128; Boolean TRUE / FALSE) was die Instanzen auf ein Minimum reduziert.

Im übrigen würden dann deine Tests sogar zu true ausgewertet werden, weil der Compiler das Autoboxing nämlich genau mit diesen .valueOf()-Methoden realisiert. Nur bei Double werden immer neue Instanzen erzeugt, weswegen dein Test auch fehlschlägt. ;)

Eine Wrapper-Instanz mit new zu erzeugen ist ähnlich wie bei einem String: Es wird sehr selten wirklich benötigt.
 
Zuletzt bearbeitet:
Vielen Dank. Dann habe ich das richtig begriffen. Aber folgende beiden Eingaben sind doch dann identisch, oder?
Java:
Integer a = Integer.valueof(2);
Integer b = 2;

Grüße

Nachtrag: Obwohl, eigentlich hast du das ja schon gesagt. valueof() benutzen und fertig ;-)
 
Zuletzt bearbeitet:

arilou

Bekanntes Mitglied
Die ursprüngliche Idee, um Speicherplatz zu sparen Wrapper-Objekte anstatt primitive Variablen zu verwenden, ist an sich bereits hirnrissig.
Die größten "primitiven" sind long (8 Byte) und double (8 Byte). Für Wrapper-Objekte wird zumindest für jedes Objekt eine Referenzvariable (ein "Pointer") benötigt, und der ist -na, ratet mal- 64 Bit groß, um unter einer 64-Bit-JVM auch mehr als 2 GB Heap verwalten zu können. Man spart also gar keinen Speicherplatz durch Wrapper-Objekte.
 

nvidia

Bekanntes Mitglied
[...]Objekt eine Referenzvariable (ein "Pointer") benötigt, und der ist -na, ratet mal- 64 Bit groß, um unter einer 64-Bit-JVM auch mehr als 2 GB Heap verwalten zu können. [...]

Das ist nicht richtig, die JVM komprimiert Pointer bis zu einem benötigten Heap von 32GB, erst dann werden die vollen 64Bit für Adressen verwendet. Nachzulesen hier Java
 

arilou

Bekanntes Mitglied
@nvidia: Danke, da hab' auch ich wieder mal etwas gelernt ;-)
D.h. man kann Ram sparen wenn
  • es um long oder double geht UND
  • viele benötigt werden UND
  • viele davon exakt identisch sind, so dass Java dann jeweils dasselbe Wrapper-Objekt verwendet.
'Ne Menge "Wenn"s.
 

nvidia

Bekanntes Mitglied
@nvidia: Danke, da hab' auch ich wieder mal etwas gelernt ;-)
D.h. man kann Ram sparen wenn
  • es um long oder double geht UND
  • viele benötigt werden UND
  • viele davon exakt identisch sind, so dass Java dann jeweils dasselbe Wrapper-Objekt verwendet.
'Ne Menge "Wenn"s.

Wenn speichersparend agiert werden soll dann sind die primitiven Typen und Arrays das Effizienteste. Die Pools der Wrapper sind nicht so groß, da wird nur in einem kleinen Wertebereich gecached. Für Integer ist das glaube ich nur -128-+127 und man muss die Objekte mit Integer.valueOf() erzeugen sonst wird der Pool gar nicht angesprochen. Zusätzlich wird noch Overhead durch die Poolverwaltung erzeugt.

Richtig auffällig ist es bei den typischen Collections, eine HashMap hat einen unglaublichen Overhead wenn man mit "einfachen" Typen arbeiten möchte. Spielt Speicher eine Rolle muss man fast auf Drittanbieterbibliotheken zurückgreifen (Trove, Colt usw.)

Also RAM spart man mit der Verwendung von Wrappern eher wenig, was man sich hauptsächlich spart ist das Erzeugen und das kann erheblich sein auch wenn scheinbar überall propagiert wird das die JVM ganz toll und schnell ist beim Erzeugen von Objekten. Bei vielen Millionen Objekten die erzeugt werden ist es immer noch durchaus sinnvoll diese (selbst) zu cachen wenn die Werte dafür fest sind. Speicher spart das aber nicht.
 

Thallius

Top Contributor
Also RAM spart man mit der Verwendung von Wrappern eher wenig, was man sich hauptsächlich spart ist das Erzeugen und das kann erheblich sein auch wenn scheinbar überall propagiert wird das die JVM ganz toll und schnell ist beim Erzeugen von Objekten. Bei vielen Millionen Objekten die erzeugt werden ist es immer noch durchaus sinnvoll diese (selbst) zu cachen wenn die Werte dafür fest sind. Speicher spart das aber nicht.

So sehen ich das auch. Nur wenn ich primitive benutzen kann, dann brauche ich überhaupt keine Erstellung. Also sehe ich auch keinen Vorteil von einem Objekt Double oder Integer im Bezug auf Speicher oder Geschwindigkeit.

Wenn ich große Datenmengen habe, muss ich doch sowiso irgendwann diese von der Platte holen und mit einem caching arbeiten.

Gruss

Claus
 

Ähnliche Java Themen

Neue Themen


Oben