Ich habe über Generationen und großen Objekthaufen gelesen. Aber ich verstehe immer noch nicht, welche Bedeutung (oder welchen Nutzen) es hat, einen großen Objekthaufen zu haben?
Was hätte schief gehen können (in Bezug auf Leistung oder Speicher), wenn sich CLR beim Speichern großer Objekte nur auf Generation 2 verlassen hätte (wenn man bedenkt, dass der Schwellenwert für Gen0 und Gen1 klein ist, um große Objekte zu handhaben)?
.net
garbage-collection
clr
large-object-heap
Manish Basantani
quelle
quelle
Antworten:
Eine Garbage Collection entfernt nicht nur nicht referenzierte Objekte, sondern komprimiert auch den Heap. Das ist eine sehr wichtige Optimierung. Dies macht nicht nur die Speichernutzung effizienter (keine nicht verwendeten Lücken), sondern auch den CPU-Cache wesentlich effizienter. Der Cache ist bei modernen Prozessoren eine große Sache, sie sind eine einfache Größenordnung schneller als der Speicherbus.
Die Komprimierung erfolgt einfach durch Kopieren von Bytes. Das braucht jedoch Zeit. Je größer das Objekt ist, desto wahrscheinlicher überwiegen die Kosten für das Kopieren die möglichen Verbesserungen der CPU-Cache-Nutzung.
Deshalb haben sie eine Reihe von Benchmarks durchgeführt, um den Break-Even-Punkt zu bestimmen. Und kam zu 85.000 Bytes als Grenzwert, an dem das Kopieren die Leistung nicht mehr verbessert. Mit einer besonderen Ausnahme für Double-Arrays gelten sie als "groß", wenn das Array mehr als 1000 Elemente enthält. Dies ist eine weitere Optimierung für 32-Bit-Code. Der Heap-Allokator für große Objekte verfügt über die spezielle Eigenschaft, dass er Speicher an Adressen zuweist, die auf 8 ausgerichtet sind, im Gegensatz zum regulären Generations-Allokator, der nur auf 4 ausgerichtet ist. Diese Ausrichtung ist eine große Sache für das Doppelte Das Lesen oder Schreiben eines falsch ausgerichteten Doppels ist sehr teuer. Seltsamerweise erwähnen die spärlichen Microsoft-Informationen niemals lange Arrays, nicht sicher, was damit los ist.
Fwiw, es gibt viele Programmiererangst darüber, dass der große Objekthaufen nicht komprimiert wird. Dies wird immer dann ausgelöst, wenn Programme geschrieben werden, die mehr als die Hälfte des gesamten verfügbaren Adressraums belegen. Verwenden Sie anschließend ein Tool wie einen Speicherprofiler, um herauszufinden, warum das Programm bombardiert wurde, obwohl noch viel nicht verwendeter virtueller Speicher verfügbar war. Ein solches Werkzeug zeigt die Löcher im LOH, unbenutzte Speicherblöcke, in denen zuvor ein großes Objekt lebte, aber Müll gesammelt wurde. Dies ist der unvermeidliche Preis des LOH. Das Loch kann nur durch eine Zuordnung für ein Objekt mit gleicher oder kleinerer Größe wiederverwendet werden. Das eigentliche Problem besteht darin, dass ein Programm jederzeit den gesamten virtuellen Speicher belegen darf .
Ein Problem, das ansonsten vollständig verschwindet, wenn nur der Code auf einem 64-Bit-Betriebssystem ausgeführt wird. Bei einem 64-Bit-Prozess stehen 8 Terabyte Adressraum für den virtuellen Speicher zur Verfügung, 3 Größenordnungen mehr als bei einem 32-Bit-Prozess. Ihnen können einfach keine Löcher ausgehen.
Kurz gesagt, das LOH macht den Code effizienter. Auf Kosten der Nutzung des verfügbaren virtuellen Speicheradressraums weniger effizient.
UPDATE, .NET 4.5.1 unterstützt jetzt das Komprimieren der Eigenschaft LOH, GCSettings.LargeObjectHeapCompactionMode . Beachten Sie bitte die Konsequenzen.
quelle
Wenn die Größe des Objekts größer als ein festgelegter Wert ist (85000 Byte in .NET 1), wird es von CLR in den Heap für große Objekte verschoben. Dies optimiert:
nieselten komprimiert)quelle
Der wesentliche Unterschied zwischen SOH (Small Object Heap) und LOH (Large Object Heap) besteht darin, dass der Speicher in SOH beim Sammeln komprimiert wird, LOH jedoch nicht, wie in diesem Artikel dargestellt. Das Verdichten großer Objekte kostet viel. Ähnlich wie bei den Beispielen im Artikel benötigt das Verschieben eines Bytes im Speicher 2 Zyklen, und das Komprimieren eines 8-MB-Objekts in einem 2-GHz-Computer benötigt 8 ms, was hohe Kosten verursacht. Angesichts der Tatsache, dass große Objekte (in den meisten Fällen Arrays) in der Praxis weit verbreitet sind, ist dies vermutlich der Grund, warum Microsoft große Objekte in den Speicher steckt und LOH vorschlägt.
Übrigens, laut diesem Beitrag erzeugt LOH normalerweise keine Speicherfragmentprobleme.
quelle
Das Prinzip ist, dass es unwahrscheinlich (und möglicherweise ein schlechtes Design) ist, dass ein Prozess viele kurzlebige große Objekte erstellt, sodass die CLR große Objekte einem separaten Heap zuordnet, auf dem GC nach einem anderen Zeitplan als dem regulären Heap ausgeführt wird. http://msdn.microsoft.com/en-us/magazine/cc534993.aspx
quelle
Ich bin kein Experte für die CLR, aber ich würde mir vorstellen, dass ein dedizierter Heap für große Objekte unnötige GC-Sweeps der vorhandenen Generationsheaps verhindern kann. Das Zuweisen eines großen Objekts erfordert eine erhebliche Menge an zusammenhängendem freiem Speicher. Um dies aus den verstreuten "Löchern" in den Generationshaufen zu erhalten, benötigen Sie häufige Komprimierungen (die nur mit GC-Zyklen durchgeführt werden).
quelle