Java-Sammlungen: Was passiert, wenn "Größe" "int" überschreitet?

7

Ich weiß, dass Java-Sammlungen sehr speicherhungrig sind und haben selbst einen Test gemacht, was beweist, dass 4 GB kaum ausreichen, um einige Millionen Integer s in HashSet zu speichern.

Aber was, wenn ich "genug" Speicher habe? Was würde mit Collection.size() geschehen?

BEARBEITEN: Gelöst: Collection.size() gibt Integer.MAX zurück, wenn der Integer-Bereich überschritten wird.
Neue Frage: wie die "echte" Anzahl von Elemente einer Sammlung dann?

ANMERKUNG 1: Entschuldigung, das ist wahrscheinlich eine Frage, die mich googeln lässt, aber ich habe wirklich nichts gefunden;)

ANMERKUNG 2: Soweit ich es verstehe, ist jeder ganzzahlige Eintrag einer Menge: reference + cached_hashcode + boxed_integer_object + real_int_value , richtig?

Hinweis 3: Lustig, sogar mit JDK7 und "komprimierten Zeigern", wenn die JVM 2 GB reellen Speicher verwendet, zeigt sie nur 1,5 GB zugewiesenen Speicher in VisualVM .

Für diejenigen, die sich interessieren:

Testquellen:

%Vor%

Ausführungsparameter:

Getestet mit der x64-Version von JDK7 Build 105 unter OpenSuse 11.3 x64.

%Vor%

Ausgabeergebnis:

%Vor%

Am Ende wurden ungefähr 2 GiB realer Speicher anstelle von 1,3 GiB verwendet, so dass der Verbrauch für jeden Eintrag noch größer als 53 Bytes ist.

    
java.is.for.desktop 23.08.2010, 13:11
quelle

4 Antworten

5

Ihre Frage scheint einen ganz anderen Inhalt zu haben als der Titel.

Sie haben die Frage bereits im Titel beantwortet ( Integer.MAX_VALUE wird zurückgegeben). Und nein: Es gibt keine Möglichkeit, die "wahre" Größe mit den normalen APIs herauszufinden, die für das Iterieren über die Sammlung und das Zählen sicher sind (mit long natürlich).

Wenn Sie Set von int -Werten speichern möchten und Sie wissen, dass die Werte für den Bereich und sehr groß werden können, dann ist möglicherweise eine BitSet eine bessere Implementierung :

%Vor%

Dies erzeugt eine Datenstruktur mit konstanter Größe, die alle Werte innerhalb des Bereichs enthalten kann, ohne die Größe zu ändern und eine relativ kleine Menge an Speicher zu belegen (1 Bit pro möglichem Wert plus etwas Overhead).

Diese Methode hat jedoch zwei Nachteile:

  • es unterstützt keine negativen int -Werte
  • es bietet nicht die Set API

Beides kann leicht umschrieben werden, indem ein Wrapper geschrieben wird, der zwei BitSet -Objekte (möglicherweise träge zugewiesen) verwendet, um den positiven bzw. negativen Wertebereich zu halten, und Adaptermethoden für die Set -Schnittstelle implementiert.

    
Joachim Sauer 23.08.2010, 14:11
quelle
14
  

Ich weiß, dass Java-Sammlungen sehr sind   Gedächtnis-hungrig, und machte einen Test selbst,   beweisen, dass 4GB gerade genug ist   speichere ein paar Millionen von Integers in einem    HashSet .

Java Heap! = Systemspeicher. Die Standard-Heap-Größe von Java beträgt nur 128 MB. Beachten Sie, dass sich dies auch von dem Speicher unterscheidet, den die JVM verwendet.

In Bezug auf Ihre Frage: aus den Dokumenten,

public int size()

  

Gibt die Anzahl der Elemente in diesem Feld zurück   Sammlung. Wenn diese Sammlung   enthält mehr als Integer.MAX_VALUE   Elemente, gibt Integer.MAX_VALUE zurück.

    
quantumSoup 23.08.2010 13:16
quelle
3

Aus dem Quellcode:

%Vor%     
Ido Weinstein 23.08.2010 13:20
quelle
0

Die allgemeine Antwort für jede echte Prozessorarchitektur ist, dass Sie es einfach nicht können. Der Grund ist einfach: Es kann nicht mehr zugewiesene Objekte (von mindestens 1 Wortgröße) als adressierbaren Speicher geben.

Angesichts der virtuellen Natur der JVM gibt es natürlich ein Szenario, in dem das passieren kann. int ist immer 32bit signiert, und Sie können die JVM auf einer 64bit-Maschine implementieren und ausführen, auf der mehr als 2 GB Speicher adressiert werden können.

In diesem Fall sagt uns die Dokumentation, dass Integer.MAX_INT zurückgegeben würde ... Und das ist ein großes Problem, weil jede Schleife, die eine Integer-Variable verwendet, die auf i < col.size() stopt, für immer läuft (obwohl ich denke, dass alles, was 2**31-1 mal loop macht, würde lange genug dauern, um den Prozess sowieso beenden zu müssen.)

    
fortran 23.08.2010 15:53
quelle