Ich werde buchstäblich Dutzende Millionen von Instanzen einer Klasse MyClass haben und möchte seine Speichergröße minimieren. Die Frage, wie viel Speicherplatz ein Objekt im Speicher beansprucht, wurde in Ermitteln Sie die Größe eines .net-Objekts Ich entschied mich, dem Vorschlag von Jon Skeet zu folgen, und das ist mein Code:
%Vor%Ich starte das Programm auf 64-Bit-Windows, wähle "release", plattform target: "any cpu", und wähle "optimize code" (Die Optionen sind nur wichtig, wenn ich explizit x86 anvisiere) Das Ergebnis ist leider 48 Bytes pro Instanz.
Meine Berechnung wäre 8 Bytes pro Referenz, plus 1 Byte für bool plus etwa 8 Byte Overhead. Was ist los? Ist das eine Verschwörung, um die RAM-Preise hoch zu halten und / oder nicht-Microsoft-Code aufblähen zu lassen? Nun, ok, ich denke, meine eigentliche Frage ist: Was mache ich falsch oder wie kann ich die Größe von MyClass minimieren?
Edit: Ich entschuldige mich dafür, in meiner Frage schlampig zu sein, ich habe ein paar Bezeichnernamen bearbeitet. Meine konkrete und unmittelbare Aufgabe war es, eine "2-dim linked-list" als spärliche boolesche Matrizen-Implementierung zu erstellen, in der ich eine Aufzählung von gesetzten Werten in einer gegebenen Zeile / Spalte leicht erhalten kann. [Das heißt natürlich, dass ich auch die x, y-Koordinaten auf der Klasse speichern muss, was meine Idee noch weniger durchführbar macht]
Nähern Sie sich dem Problem vom anderen Ende. Anstatt sich zu fragen, "wie kann ich diese Datenstruktur verkleinern und immer noch zig Millionen von ihnen zugewiesen bekommen?" Fragen Sie sich: "Wie kann ich diese Daten mit einer völlig anderen Datenstruktur darstellen, die viel kompakter ist?"
Es sieht so aus, als ob Sie eine doppelt verknüpfte Liste von Bools erstellen, die, wie Sie bemerken, dreißig bis fünfzig Mal mehr Speicher benötigt, als sie benötigen. Gibt es einen Grund, warum Sie nicht einfach ein BitArray
verwenden Speichern Sie Ihre Liste der Bools?
UPDATE:
Tatsächlich habe ich versucht, eine spärliche boolesche zweidimensionale Matrix zu implementieren
Nun, warum hast du das nicht gesagt?
Wenn ich eine spärliche boolesche zweidimensionale Matrix von enormer Größe erstellen möchte, erstelle ich einen unveränderlichen persistenten booleschen Quadtree mit einer Memo-Factory. Wenn das Array spärlich ist, oder selbst wenn es dicht ist, aber in gewisser Weise selbstähnlich ist, können Sie enorme Komprimierungen erzielen. Quadratische Arrays von 2 Booleans sind leicht darstellbar, obwohl sie offensichtlich als ein reales Array mehr Speicher als in der Welt sind.
Ich habe mit der Idee gespielt, eine Reihe von Blogartikeln über diese Technik zu machen; Ich werde es wahrscheinlich Ende März tun.
Kurz gesagt, besteht die Idee darin, eine abstrakte Klasse Quad zu erstellen, die zwei Unterklassen hat: Single und Multi. "Single" ist ein Doubleton - wie ein Singleton, aber mit genau zwei Instanzen, genannt True und False. Ein Multi ist ein Quad, das vier Unter-Quads hat, die als NorthEast, SouthEast, SouthWest und NorthWest bezeichnet werden.
Jedes Quad hat eine ganze Zahl "level"; Die Stufe eines einzelnen ist Null, und ein Vielfaches von Niveau n ist erforderlich, damit alle seine Kinder Quads der Stufe n-1 sind.
Die Mehrfachfabrik ist angemeldet; Wenn Sie es bitten, ein neues Multi mit vier Kindern zu machen, konsultiert es einen Cache, um zu sehen, ob es es vorher gemacht hat. Wenn es so ist, baut es kein neues; es teilt das alte aus. Da Quads unveränderbar sind, müssen Sie sich keine Sorgen darüber machen, dass jemand das Quad bei Ihnen ändert, nachdem es sich im Cache befindet.
Betrachten Sie nun, wie viele Speicherworte (ein Wort ist 4 oder 8 Bytes je nach Architektur) ein "alles falsches" Multi der Ebene n verbraucht. Ein "all false" -Multi der Stufe 1 konsumiert vier Wörter für die Links zu seinen Kindern, ein Wort für die Levelanzahl (wenn nötig; Sie sind nicht verpflichtet, das Level im Multi zu halten, obwohl es beim Debuggen hilft) und ein paar Wörter für den Sync-Block und so weiter. Nennen wir es acht Worte. (Plus die Erinnerung für das False Single Quad, das wir annehmen können, ist eine Konstante zwei oder drei Wörter, und dadurch kann ignoriert werden.)
Ein Level 2 "all false" Multi konsumiert die gleichen acht Wörter, aber jedes seiner vier Kinder ist dasselbe Level 1 multi . Daher ist der Gesamtverbrauch der Ebene 2 "alles falsch" Multi sagen wir 16 Worte.
Das gleiche gilt für die Level 3, 4, ... und so weiter. Der gesamte Speicherverbrauch für ein Niveau 64 multi, das logisch eine 2 64 x 2 64 quadratische Anordnung von Booleans ist, ist nur 64 x 16 Gedächtniswörter!
Sinn machen? Hoffentlich ist das genug von einer Skizze, um dich in Gang zu bringen. Wenn nicht, siehe mein Blog Ende März.
8 (Objektreferenz) + 8 (Objektreferenz) + 1 (bool) + 16 (Header) + 8 (Referenz im Array selbst) = 41
Auch wenn es intern falsch ausgerichtet ist, werden alle auf dem Heap ausgerichtet. Wir suchen also mindestens 48 Bytes.
Ich kann nicht für das Leben von mir sehen, warum Sie eine verknüpfte Liste von Bools wünschen. Eine Liste von ihnen würde 48 mal weniger Speicherplatz benötigen, und das ist bevor Sie Optimierungen für die Speicherung eines Bool pro Bit vornehmen, was es 384 mal kleiner machen würde. Und einfacher zu manipulieren.
Wenn diese Hunderte von Millionen von Instanzen der Klasse hauptsächlich Kopien der Klasse mit geringfügigen Variationen der Klasseneigenschaftswerte sind, dann ist Ihr System ein Hauptkandidat für die Verwendung des sogenannten Flyweight Muster. Dieses Muster minimiert die Speicherausnutzung, indem dieselben Instanzen immer und immer wieder verwendet werden und nur die Eigenschaften nach Bedarf geändert werden ...
Tags und Links c# memory-management