2016-06-01 16 views
3

Ich habe einige Code, den ich ein verschachteltes Wörterbuch hinzugefügt, im folgenden FormatSpeichernutzung von Wörterbücher in C#

Dictionary<string, Dictionary<string, Dictionary<string, float>>> 

Nachdem damit ich die Speichernutzung meiner Anwendung DEUTLICH geschossen bemerkt. Diese Wörterbücher werden auf Strings getaktet, die oft wiederholt werden, und es gibt viele dieser Wörterbücher in der Größenordnung von Zehntausenden.

Um dieses Problem anzugehen, stellte ich die Hypothese auf, dass die wiederholten Strings eine beträchtliche Menge an Speicher auffressen. Meine Lösung war die Saiten Hash und eine ganze Zahl zu verwenden, anstatt (I eine Kopie einer Rainbow-Tabelle halten würde, so konnte ich den Hash umkehren, wenn nötig)

Dictionary<int, Dictionary<int, Dictionary<int, float>>> 

Also ich zu einem Speicher-Profiler ging, um zu sehen, welche Art von Größenreduzierung könnte ich bekommen. Zu meinem Schrecken fand ich tatsächlich, dass der String-Speicher tatsächlich kleiner war (sowohl normal als auch inklusive).

Das macht keinen intuitiven Sinn für mich. Selbst wenn der Compiler klug genug wäre, nur eine Kopie der Zeichenfolge zu speichern und eine Referenz zu verwenden, würde ich meinen, dass die Referenz ein Zeiger sein würde, der doppelt so groß ist wie ein int. Ich habe auch keine String.Intern Methoden verwendet, so weiß ich nicht, wie dies erreicht worden wäre (ist auch String.Intern die richtige Methode hier?)

Ich bin sehr verwirrt, was passiert unter der Haube, jede Hilfe würde geschätzt werden

+3

Nichts besonderes wird unter der Haube getan. Entweder hat Ihre Internierungsstrategie nicht viel Redundanz beseitigt oder es gibt einen Fehler. Sie müssen Code schreiben. – usr

+1

Vielleicht können Sie ein 'Dictionary >' verwenden, um die Verschachtelung loszuwerden. 'Dictionary' ist kein kleiner Typ. Verwenden Sie ein Strukturtupel. – usr

+2

"schoss SIGNIFIKANT." - verglichen mit was? (Beachten Sie, dass http: // stackoverflow.com/questions/20430157/Speicher-Verwendung-of-Dictionary-in-c-sharp kann als doppeltes Ziel für Ihre Frage verwendet werden, es sei denn, Sie klären, wie es nicht ist) –

Antwort

4

Wenn Ihre Schlüssel und Werte Objekte sind, gibt es etwa 20 Bytes Overhead für jedes Element eines Wörterbuchs plus einige weitere Bytes pro Wörterbuch. Dies ist zusätzlich zu dem Platz, den die Schlüssel und Werte selbst verbrauchen. Wenn Sie Werttypen als Schlüssel und Werte haben, sind es 12 Byte plus der Platz, den der Schlüssel und der Wert für jedes Element im Wörterbuch verbrauchen. Dies ist der Fall, wenn die Anzahl der Elemente der Kapazität des internen Wörterbuchs entspricht. Aber normalerweise gibt es mehr Kapazität als Elemente, also verschwendeter Platz.

Der verschwendete Speicherplatz ist im Allgemeinen ein höherer relativer Prozentsatz, wenn Sie viele Wörterbücher mit einer kleinen Anzahl von Elementen haben, als wenn Sie ein Wörterbuch mit vielen Elementen hätten. Wenn ich nach Ihrem Kommentar gehe, haben Ihre Wörterbücher mit 8 Elementen eine Kapazität von 11, diejenigen mit 2 Elementen haben eine Kapazität von 3 und diejenigen mit 10 Elementen haben eine Kapazität von 11.

Wenn ich Ihre Verschachtelung verstehe zählt, dann wird ein einzelnes Top-Level-Wörterbuch 184 Wörterbuchelemente darstellen. Wenn wir jedoch die ungenutzte Kapazität zählen, liegt sie beim Speicherplatzbedarf näher bei 200. 200 * 20 = 4000 Bytes für jedes Wörterbuch der obersten Ebene. Wie viele von denen hast du? Sie sagen Zehntausende von ihnen in tausend Objekten. Jeder 10.000 wird etwa 38 MB Wörterbuch-Overhead verbrauchen. Fügen Sie dazu die Objekte hinzu, die im Wörterbuch gespeichert sind.

Eine mögliche Erklärung, warum Ihr Versuch, es durch die Verwaltung der Hash-Codes zu verkleinern, wäre, wenn es nicht viele doppelte Referenzen auf Ihre Schlüssel gibt. Durch das Ersetzen eines Objektreferenzschlüssels durch einen Int-Schlüssel wird der Dictionary Overhead-Betrag nicht geändert, und Sie fügen den Speicher Ihrer neuen Sammlung von Hashcodes hinzu.