Ich habe eine ziemlich einfache C # -Anwendung, die eine große Hashtabelle erstellt hat. Die Schlüssel dieser Hashtabelle sind Strings und die Werte sind Ints.
Das Programm läuft gut, bis etwa 10,3 Millionen Elemente zur Hashtabelle hinzugefügt wurden, wenn ein Fehler wegen zu wenig Speicher in der Zeile erscheint, die der hasbtable ein Element hinzufügt.
Laut dem Task-Manager verwendet mein Programm nur 797 MB Speicher, und es sind immer noch mehr als 2 GB verfügbar. Es ist eine 32-Bit-Maschine, also weiß ich, dass nur ein Gesamtwert von 2 GB von einem Prozess verwendet werden kann, aber das lässt immer noch etwa 1,2 GB übrig, in die die Hashtabelle expandieren könnte.
Warum wird ein Fehler wegen zu wenig Speicher ausgegeben?
Theoretisch erhalten Sie 2 GB für den Prozess, aber die Realität ist, dass es 2 GB zusammenhängender Speicher ist. Wenn also der Speicher Ihres Prozesses fragmentiert ist, erhalten Sie weniger als das.
Außerdem vermute ich, dass die Hash-Tabelle wie die meisten Datenstrukturen standardmäßig verdoppelt wird, wenn sie wachsen muss, was zu einem großen Wachstum führt, wenn der Tipppunkt hinzugefügt wird.
Wenn Sie die Größe kennen, die im Voraus benötigt wird (oder eine angemessene Überschätzung haben), kann es hilfreich sein, die Kapazität im Konstruktor anzugeben.
Alternativ, wenn es nicht entscheidend ist, dass es im Speicher ist, kann eine Art von Datenbanklösung besser sein und Ihnen mehr Flexibilität geben, wenn es den Punkt erreicht, dass es nicht in den Speicher passen kann.
Wahrscheinlich liegt das an der Speicherfragmentierung: Sie haben immer noch freien Speicher, aber nicht zusammenhängend. Der Speicher ist in Seiten unterteilt, normalerweise 4 KB groß. Wenn Sie also 4 MB zuweisen, benötigen Sie 1024 zusammenhängende Speicherseiten in Ihrem Prozessadressraum (sie sind nicht < em> physisch zusammenhängend, da der Speicher pro Prozess virtualisiert wird.
Allerdings muss der Speicher für die Hashtabelle nicht zusammenhängend sein (es sei denn, es ist sehr schlecht implementiert), also ist es vielleicht eine Grenze des Speichermanagers ...
Verwenden Sie Process Explorer (www.sysinternals.com) und sehen Sie sich den virtuellen Adressraum Ihres Prozesses an. Im Gegensatz zu "Private Bytes" (dh der Speichermenge, die vom Prozess belegt wird) zeigt der virtuelle Adressraum die höchste verwendete Speicheradresse an. Wenn die Fragmentierung hoch ist, ist sie viel höher als die "Private Bytes".
Wenn Ihre Anwendung wirklich so viel Speicher benötigt:
Das Programm, das Sie ausführen, hat begrenzte Ressourcen dank des Visual Studio-Debuggers, der versucht, alles zu verfolgen, was Sie in Ihrer Anwendung tun (Haltepunkte, Referenzen, Stapel usw.).
Darüber hinaus haben Sie möglicherweise mehr Dinge, die noch nicht intakt sind, als Sie denken. Der Garbage Collector ist abgestuft und sammelt langsam große Objekte sehr .
%Vor%HINWEIS: Die Zahlen sind aus dem Speicher, also nehmen Sie es mit einem Körnchen Salz.