Warum bekomme ich einen OutOfMemoryError beim einfügen von 50.000 Objekte in die HashMap?
Ich versuche zu legen, die etwa 50.000 Objekten (und somit auch die 50.000 keys) in einer java.util.HashMap<java.awt.Point, Segment>
. Allerdings habe ich immer eine OutOfMemory-exception. (Segment
ist meine eigene Klasse - sehr geringes Gewicht - ein String
Feld und 3 int
Felder).
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space bei java.util.HashMap.Größe(HashMap.java:508) bei java.util.HashMap.addEntry(HashMap.java:799) bei java.util.HashMap.put(HashMap.java:431) at-bus.tools.UpdateMap.putSegment(UpdateMap.java:168)
Das erscheint mir ziemlich lächerlich, weil ich sehe, dass es viel Speicher auf dem Gerät verfügbar - sowohl in der freien RAM-und Festplattenspeicher für den virtuellen Speicher.
Ist es möglich, Java ausgeführt wird, mit einigen strengen Anforderungen an den Arbeitsspeicher? Erhöhe ich diese?
Gibt es einige seltsame Einschränkung mit HashMap
? Bin ich zu haben, zu implementieren? Gibt es andere Klassen, die zu betrachten sich lohnt?
(Ich arbeite mit Java 5 unter OS X 10.5 auf einem Intel-Rechner mit 2 GB RAM.)
InformationsquelleAutor der Frage Frank Krueger | 2008-10-24
Du musst angemeldet sein, um einen Kommentar abzugeben.
Erhöhen Sie die maximale heap-Größe von passing-Xmx128m (wo 128 ist die Anzahl der Megabyte) auf java. Ich kann mich nicht erinnern, die Standard-Größe, aber es scheint mir, dass es war eher etwas klein.
Können Sie programmgesteuert überprüfen, wie viel Speicher verfügbar ist, indem Sie mit der Laufzeit Klasse.
(Beispiel aus Java-Entwickler-Almanach)
Dies ist auch teilweise in Angriff genommen in Häufig Gestellte Fragen Über die Java-HotSpot-VMund in der Java 6 GC-Tuning-Seite.
InformationsquelleAutor der Antwort Michael Myers
Einige Leute schlagen vor, die änderung der Parameter der HashMap zu einer Verschärfung der Anforderungen an den Arbeitsspeicher. Ich würde vorschlagen, um Messen statt raten; es wäre etwas anderes verursacht die OOME. Insbesondere empfehle ich entweder NetBeans Profiler oder VisualVM (die kommt mit Java 6, aber ich sehe, Sie stecken mit Java-5).
InformationsquelleAutor der Antwort Michael Myers
Andere Sache, zu versuchen, wenn Sie wissen, die Anzahl der Objekte vorher ist die Verwendung der HashMap(int Kapazität,Doppel-loadfactor) - Konstruktor anstelle des Standard-no-arg-one verwendet standardmäßig (16,0.75). Wenn die Anzahl der Elemente in der HashMap übersteigt (Kapazität * loadfactor) die zugrunde liegenden Arrays in die HashMap wird in der Größe verändert werden, um die nächste Potenz von 2 und die Tabelle wird aufgewärmt. Das array erfordert auch einen zusammenhängenden Bereich im Speicher, so zum Beispiel, wenn Sie verdoppeln, aus einem 32768 zu einer Größe 65536 array benötigen Sie einen 256 KByte Speicherblock frei. Um zu vermeiden, die zusätzliche Zuordnung und Aufbereitung Strafen, benutzen Sie einfach eine größere hash-Tabelle von Anfang an. Es wird auch verringern die chance, dass Sie nicht haben, ein zusammenhängender Speicherbereich groß genug, um die Karte.
InformationsquelleAutor der Antwort sk.
Sind die Implementierungen unterstützt von arrays, die in der Regel. Arrays fester Größe Speicherblöcke. Die hashmap-Implementierung beginnt mit der Speicherung von Daten in eines dieser arrays auf einer gegebenen Kapazität, sagen 100 Objekte.
Wenn es füllt das array und halten Sie das hinzufügen von Objekten, die Karte muss heimlich erhöhen Sie Ihre array-Größe. Da arrays sind festgelegt, es tut dies, indem Sie erstellen ein völlig neues array im Speicher, zusammen mit dem aktuellen array, das ist etwas größer. Dies bezeichnet man als wachsendes array. Dann alle Elemente vom alten array werden in das neue array und das alte array wird aufgelöst, mit der Hoffnung, es wird Müll gesammelt, und der Speicher freigegeben.
In der Regel den code, der erhöht die Kapazität der Karte durch das kopieren von Elementen in ein größeres array ist die Ursache für solch ein problem. Es gibt "dumme" Implementierung und die klugen, die mit einem Wachstums-oder load-Faktor, der bestimmt die Größe des neuen Arrays basierend auf der Größe des alten Arrays. Einige Implementierungen verstecken diese Parameter und einige nicht, so dass Sie nicht immer gesetzt. Das problem ist, wenn nicht, wählt es einige Standard-Auslastung, die wie 2. So wird das neue array der doppelten Größe der alten. Jetzt ist Ihre angeblich 50k Karte hat eine backing-array von 100k.
Schauen, um zu sehen, wenn Sie können, reduzieren Sie die Auslastung bis zu 0,25 oder sowas. dies bewirkt, dass mehr hash-Tabelle die Kollisionen, die beeinträchtigt die Leistung aber Sie sind zu schlagen, ein Speicher-Engpass und die Notwendigkeit, dies zu tun.
Verwenden Sie diesen Konstruktor:
(http://java.sun.com/javase/6/docs/api/java/util/HashMap.html#HashMap(intfloat))
InformationsquelleAutor der Antwort Josh
Müssen Sie wahrscheinlich, um die Flagge -Xmx512m oder eine größere Anzahl beim Start von java. Ich denke, dass 64 MB " ist die Standardeinstellung.
Bearbeitet, um hinzufügen:
Nachdem Sie herausfinden, wie viel Speicher Ihre Objekte tatsächlich mit einem profiler, möchten Sie vielleicht zu schauen, in schwache Verweise oder soft-Referenzen, um sicherzustellen, dass Sie nicht versehentlich holding einige Ihrer Speicher-Geisel aus den garbage collector, wenn Sie Sie nicht mehr benutzen.
InformationsquelleAutor der Antwort JasonTrue
Könnte auch wollen, werfen Sie einen Blick auf diese:
http://java.sun.com/docs/hotspot/gc/
InformationsquelleAutor der Antwort Allain Lalonde
Implizit in diese antwortet ihm, dass Java eine Feste Größe für das Gedächtnis und das wächst nicht über die konfigurierte maximale heap-Größe. Dies ist im Gegensatz zu, sagen wir, C, wo es eingeschränkt nur durch den Computer auf dem es ausgeführt wird.
InformationsquelleAutor der Antwort davetron5000
Standardmäßig die JVM verwendet eine begrenzte heap space. Die Grenze ist die JVM-Implementierung abhängig, und es ist nicht klar, was die JVM, die Sie verwenden. Auf Betriebssystemen anders als Windows, einer 32-bit Sun JVM auf einem Rechner mit 2 Gb oder mehr wird mit einem Standardwert für die maximale heap-Größe von 1/4 der physische Speicher 512 Mb in Ihrem Fall. Jedoch, die Standardeinstellung für "client" - Modus die JVM ist nur 64 Mb maximale heap-Größe, die kann was, die Sie ausgeführt haben. Andere Anbieter JVM können Sie verschiedene Standardwerte.
Natürlich können Sie die heap-Grenze explizit mit der
-Xmx<NN>m
optionjava
wo<NN>
ist die Anzahl der Megabyte für den heap.Als eine grobe Schätzung, wird Ihr hash-Tabelle sollte nur mit etwa 16 Mb, also muss es irgendeine andere große Objekte auf dem heap. Wenn Sie könnte ein
Comparable
Schlüssel in einerTreeMap
wäre, dass etwas Speicher sparen.Sehen "Ergonomie in der 5.0-JVM" für mehr details.
InformationsquelleAutor der Antwort erickson
Des Java-heap-space ist beschränkt durch den Standard, aber das klingt immer noch extrem (obwohl wie groß sind deine 50000-Segmente?)
Ich bin zu Ahnen, dass Sie einige andere problem, wie die arrays in das set zu groß, weil alles zugewiesen bekommt, die in die gleiche "slot" (auch auf die Leistung auswirkt, natürlich). Aber das scheint unwahrscheinlich, wenn Sie Ihre Punkte sind gleichmäßig verteilt.
Frage ich mich aber warum verwendest du eine HashMap statt einer TreeMap? Obwohl Punkte sind zweidimensional, Sie könnte Unterklasse diese mit einer Funktion vergleichen, und dann tun, log(n) - lookups.
InformationsquelleAutor der Antwort Uri
Zufälliger Gedanke: Der hash-buckets zugeordnet HashMap sind nicht besonders Speicher effizient. Sie möchten möglicherweise versuchen, aus TreeMap als alternative und sehen, ob Sie noch genügend Leistung haben.
InformationsquelleAutor der Antwort Kevin Day