Die Speicherauslastung und Fragmentierung von .NET Image-Klassen: Bitmap vs. Metafile

10

Aufgrund scheinbar voreiliger Out-of-Memory-Ausnahmen haben wir die Speicherbelegung verschiedener .NET-Konstrukte genau untersucht ... besonders große Objekte, die dazu neigen, den Large Object Heap zu fragmentieren, was zu vorzeitigen Out-of-Memory-Ausnahmen führt. Ein Bereich, der ein wenig überraschend ist, sind die .NET Image-Klassen: Bitmap und Metafile.

Wir glauben, dass wir gelernt haben, dass wir jedoch keine MS-Dokumentation zur Überprüfung finden konnten. Wir würden uns über jede Bestätigung freuen, die andere geben können:

(1) Wenn Sie ein Bitmap-Objekt aus einer komprimierten Rasterdatei (JPG, PNG, GIF usw.) erstellen, belegt es Speicher für ein vollständig unkomprimiertes Pixel-Array mit der vollen Auflösung dieser Datei. So würde zum Beispiel ein 5MB JPG, das 9000x3000 Pixel groß ist, in 9000x3000x3 Bytes (angenommen 24 Bit Farbe, kein Alpha) oder 81MB Speicherbedarf erweitert. Korrekt?

(1a) Es gibt einige Beweise (siehe 2b unten), dass es auch das ursprüngliche komprimierte Format speichert ... also tatsächlich 86MB in diesem Fall. Aber das ist unklar ... weiß jemand?

(2) Wenn Sie ein Metafile-Objekt erstellen und dann eine Rasterdatei (JPG, PNG, GIF usw.) darauf zeichnen, wird nur Speicher für die komprimierte Datei benötigt. Wenn Sie also ein 5MB JPG, also 9000x3000 Pixel, in eine Metafile zeichnen, werden nur etwa 5MB Speicher belegt. Korrekt?

(2a) Um eine Raster-Datei in ein Metafile-Objekt zu zeichnen, scheint der einzige Weg darin zu bestehen, ein Bitmap mit der Datei zu laden und dann die Bitmap in die Metafile zu zeichnen. Gibt es einen besseren Weg, der nicht das zeitweilige Laden dieser riesigen Bitmap-Daten beinhaltet (und die damit verbundene Speicherfragmentierung verursacht)?

(2b) Wenn Sie eine Bitmap in eine Metafile zeichnen, wird ein komprimiertes Format verwendet, dessen Größe der ursprünglichen komprimierten Datei ähnelt. Wird die ursprüngliche komprimierte Datei in der Bitmap gespeichert? Oder macht es das, indem es die erweiterte Bitmap mit den ursprünglichen Komprimierungseinstellungen erneut komprimiert?

(3) Wir gingen ursprünglich davon aus, dass große (& gt; 85KB) Bildobjekte in dem großen Objekt-Heap platziert werden würden. In der Tat scheint das nicht der Fall zu sein. Vielmehr ist jedes Bitmap und jede Metafile ein 24-Byte-Objekt im Small Object Heap, das sich auf einen Block Native Memory bezieht, der die echten Daten enthält. Korrekt?

(3a) Wir gehen davon aus, dass ein solcher nativer Speicher wie Large Object Heap ist, da er nicht kompaktiert werden kann ... sobald das große Objekt in den nativen Speicher gelegt wird, wird es niemals verschoben und somit kann die Fragmentierung des nativen Speichers dies verursachen viele Probleme als Fragmentierung von Large Object Heap. Wahr? Oder gibt es eine spezielle Behandlung der zugrunde liegenden Bitmap / Metafile-Daten, die effizienter ist?

(3b) Es scheint also vier unabhängige Speicherblöcke zu geben, die separat verwaltet werden und bei denen jeder die gleichen Out-of-Memory-Ausnahmen auslösen kann: Small Object Heap (verwaltete Objekte & lt; 85 KB, komprimiert durch die GC), Large Object Heap (verwaltete Objekte & gt; 85 KB, die von GC gesammelt, jedoch nicht komprimiert werden), Native Memory (nicht verwaltete Objekte, vermutlich nicht komprimiert) und Desktop Heap (wo Windows-Handles und solche begrenzten Ressourcen verwaltet werden). Habe ich diese vier richtig dokumentiert? Gibt es andere, denen wir uns bewusst sein sollten?

Jede Klarheit, die irgendjemand zu dem oben Gesagten bieten kann, würde sehr geschätzt werden. Wenn es ein gutes Buch oder einen Artikel gibt, der das oben genannte vollständig erklärt, lass es mich wissen. (Ich bin glücklich, die erforderliche Lektüre zu machen; aber die überwiegende Mehrheit der Bücher geht nicht so tief und erzählt mir daher nichts, was ich nicht schon weiß.)

Danke!

    
Brian Kennedy 20.03.2013, 16:54
quelle

2 Antworten

4

Es gibt zwei Möglichkeiten, Bilddaten zu speichern: als Pixel oder als Vektoren. Bitmap steht für Pixel, Metafile steht für Pixel und Vektoren. Vektordaten sind viel effizienter zu speichern.

Um die Manipulation von Bitmaps zu ermöglichen, müssen ihre Daten unkomprimiert im Speicher gespeichert werden. Andernfalls müssten GetPixel und SetPixel die Bitmap für jede Änderung dekomprimieren, ändern, neu komprimieren (falls das überhaupt möglich wäre).

Metafiles wurden von Microsoft erstellt und sollten mit GDI arbeiten, daher könnte es einige mehr speichereffiziente Komprimierungsalgorithmen enthalten arbeite direkt mit der Grafikkarte. Außerdem gibt es keine GetPixel SetPixel -Methoden für Metadateien, so dass sie nicht im Arbeitsspeicher dekomprimiert werden müssen, um eine Manipulation zu ermöglichen.

Sie sollten sich nicht um die Speicherpools kümmern, die die Laufzeitumgebung verwendet. Es gibt viel mehr, und die Laufzeit entscheidet, wo sie Objekte platziert. Außerdem sollten Sie sich nicht um Out-of-Memory-Ausnahmen kümmern, die möglicherweise durch die Verwendung von (großen) Objekten entstehen. Die Runtime wird alles tun, was möglich ist (Objekte in Lücken zwischen anderen Objekten setzen, Heaps komprimieren, verfügbaren virtuellen Speicher erweitern), um sicherzustellen, dass Sie keine Ausnahme wegen zu wenig Arbeitsspeicher erhalten. Wenn Sie eine solche Ausnahme irgendwie erhalten, gibt es wahrscheinlich ein anderes Problem in Ihrem Code, das behoben werden sollte (z. B. ein Speicherverlust).

Eine Übersicht über die Speicher-Heaps, Karten und Tabellen: ( Quelle )

Auch Ihre Annahme, dass Objekte von über 85 KiB auf dem Large Object Heap platziert sind, ist nicht ganz korrekt. Für die meisten Objekte in der aktuellen Version der CLR ist es korrekt, aber zum Beispiel wird auch ein 8 KiB Array von Doppelpunkten (1000 Doppel) auf dem Large Object Heap zugewiesen. Lass die Laufzeit sich damit beschäftigen.

    
Virtlink 20.03.2013 17:17
quelle
2

Ich kenne die Antworten auf einige von diesen:

(1) Ja, das ist die Definition eines Bitmap-Bildes.

(3) Ja, deshalb implementiert Bitmap die IDisposable-Schnittstelle.

(3a) Das erscheint überraschend. Führen Sie die Dispose () -Methode für Ihre Bitmap-Objekte aus, wenn Sie damit fertig sind?

(3b) Zumindest diese vier, ja.

    
Pieter Geerkens 20.03.2013 17:10
quelle

Tags und Links