Frage an c#, .net, garbage-collection – Wie kann nicht verwendeter Speicher aus dem großen Objekthaufen LOH von mehreren verwalteten Apps zurückgewonnen werden?

8

Während eines Gesprächs mit einem Kollegen über eine bestimmte Gruppe von Apps, die beim Start fast 1,5 GB Speicher verbrauchen, verwies er mich auf einen sehr guten Link zu.NET-Produktions-Debugging

Der Teil, der mich verwirrt hat, ist ...

Wenn Sie beispielsweise einem einzelnen Block 1 MB Speicher zuweisen, wird der Heapspeicher für große Objekte auf 1 MB erweitert. Wenn Sie dieses Objekt freigeben, wird der virtuelle Speicher durch den Heapspeicher für große Objekte nicht freigegeben, sodass die Größe des Heapspeichers 1 MB beträgt. Wenn Sie später einen weiteren 500-KB-Block zuweisen, wird der neue Block innerhalb des 1-MB-Speicherblocks zugewiesen, der zum Heap für große Objekte gehört. Während der Prozesslebensdauer wird der Heap für große Objekte immer größer, um alle derzeit referenzierten Zuordnungen für große Blöcke aufzunehmen, verkleinert sich jedoch nie, wenn Objekte freigegeben werden, selbst wenn eine Garbage Collection auftritt. Abbildung 2.4 auf der nächsten Seite zeigt ein Beispiel für einen großen Objekthaufen.

Nehmen wir an, wir haben eine fiktive App, die eine Flut von großen Objekten (> 85 KB) erzeugt, sodass der Haufen großer Objekte auf 200 Meg wächst. Nehmen wir nun an, wir haben 10 solcher App-Instanzen in Betrieb, so dass 2000 Megabyte zugewiesen werden. Jetzt wird dieser Speicher erst wieder an das Betriebssystem zurückgegeben, wenn der Prozess beendet ist ... (habe ich verstanden)

Gibt es Lücken in meinem Verständnis? Wie erhalten wir nicht verwendeten Speicher in den verschiedenen LOHeaps zurück? erstellen wir nicht den perfekten Sturm von OutOfMemoryExceptions?

Aktualisieren: Aus Marc 'Antwort wollte ich klarstellen, dass die LOH-Objekte nicht referenziert werden - die großen Objekte sind use-n-throw - jedoch schrumpft der Heap nicht, obwohl der Heap nach dem ersten Anstieg relativ leer ist.

Update Nr. 2: Einschließlich eines Code-Snippets (übertrieben, aber ich denke, das ist ein klarer Punkt). Ich sehe eine OutOfMemoryException, wenn der virtuelle Speicher auf meinem Computer die 1,5-G-Marke erreicht (auf einem anderen 1,7-G)Eric L.'s Blog Post, 'Prozessspeicher kann als massive Datei auf der Festplatte dargestellt werden.' - Dieses Ergebnis ist daher unerwartet. Die Computer in diesem Fall verfügten über GB freien Speicherplatz auf der Festplatte. Verursacht die PageFile.sys-Betriebssystemdatei (oder verwandte Einstellungen) Einschränkungen?

<code>        static float _megaBytes;
        static readonly int BYTES_IN_MB = 1024*1024;

        static void BigBite()
        {
           try
           {
              var list = new List<byte[]>();
              int i = 1;

              for (int x = 0; x < 1500; x++)
              {
                 var memory = new byte[BYTES_IN_MB + i];
                 _megaBytes += memory.Length / BYTES_IN_MB;
                 list.Add(memory);
                 Console.WriteLine("Allocation #{0} : {1}MB now", i++, _megaBytes);
              }
           }
           catch (Exception e)
           {  Console.WriteLine("Boom! {0}", e); // I put a breakpoint here to check the console
              throw;
           }
        }
       static void Main(string[] args)
        {
            BigBite();
            Console.WriteLine("Check VM now!"); Console.ReadLine();
            _megaBytes = 0;

            ThreadPool.QueueUserWorkItem(delegate { BigBite(); });
            ThreadPool.QueueUserWorkItem(delegate { BigBite(); });
            Console.ReadLine();   // will blow before it reaches here
        }
</code>
(auf Kommentar geantwortet) Marc Gravell

Deine Antwort

3   die antwort
3

liegt das am LOH - aber vergessen Sie das nichtOutOfMemoryException Dies ist prozessbezogen, da tatsächlich die Festplatte der begrenzende Faktor für den virtuellen Speicher ist. Eric Lippertdarüber gebloggt vor kurzem. Das verhindert natürlich nicht, dass das gesamte Paging zu einer schlechten Leistung führt ...

Vielen Dank für den Link ... hat einen Codeausschnitt angehängt, der mich weiter verwirrt, aber dem Problem ähnelt, mit dem dieser Thread gestartet wurde. Ihre Gedanken werden wie immer sehr geschätzt. Vielen Dank für die Arbeit, die Sie in diesem Forum leisten ... Gishu
Ich bin nicht sicher, ob die Bearbeitung etwas ändert. Der Punkt, den ich machen wollte, ist, dass ein Ball mit 200 MB und eine Kette das nicht sindNotwendig ein Problem. Das meiste davon wird wahrscheinlich aufgrund von Inaktivität aus dem Hauptspeicher verschoben ... Marc Gravell
Aktualisiert die Frage: Die LOH-Objekte selbst sind in diesem Fall "use-n-throw". Sobald sie ihren Zweck erfüllt haben, wurden die LOH-Objekte freigegeben, aber der Heap wird nicht kleiner. Stellen Sie sich eine Komponente vor, die einige Objekte serialisiert, bevor sie über eine Pipe gesendet wird. In diesem Fall weisen Sie beispielsweise 200 Megabyte als Byte-Arrays zu, die nach der Übertragung der Daten Müll sind. Gishu
2

können Sie Ihre großen Objekte in eine andere Appdomäne verschieben. Wenn Sie sich dafür entscheiden, alle großen Objekte freizugeben, geben Sie die Appdomäne frei, und der Heap für diese Appdomäne wird freigegeben.

LOH ist nicht pro Appdomain. mfawzymkh
5

die ich zuerst machen möchte. - Unter der Annahme, dass Sie die App als 32-Bit-App ausführen, beträgt der für Ihren Prozess verfügbare VA-Speicher nur 2 GB, 3 GB, wenn Sie den Switch für einen großen Adressraum aktiviert haben. Selbst wenn Sie über eine GROSSE Auslagerungsdatei verfügen, spielt dies keine Rolle, wenn Sie 32-Bit-App sind Prozess, es ist wichtig, wenn Sie 64bit ausführen, wo Sie großen Adressraum haben.

Objekt mit Größe>85000 Bytes sind auf LOH zugeordnet, beachten Sie, es ist85000 Bytes nicht 85K, es sind auch Implementierungsdetails, die sich ändern können. Nun zurück zu Ihrer Frage. Der GC hebt die Festschreibung für die LOH-Segmente auf, die in 2 Situationen nicht verwendet werden. 1- Wenn der Speicherdruck auf dem Computer hoch ist (~ 95-98%). 2- Wenn neue Zuweisungsanforderungen nicht erfüllt werden, wird die nicht verwendete Zuordnung aufgehoben Seiten im LOH

In einem dieser Fälle erhalten Sie die Erinnerung zurück. Die Tatsache, dass Sie eine OOM treffen, bevor die 2-GB-Grenze erreicht ist, kann bedeuten, dass Sie eine VA-Fragmentierung haben. Eine VA-Fragmentierung tritt auf, wenn Sie nicht über einen kontinuierlichen VA-Adressraum verfügen, um die neue Zuordnung zu erfüllen. Sie haben keine 2 aufeinanderfolgenden Seiten in Ihrer VA (vorausgesetzt, die Seitengröße beträgt 4 KB).

Sie können die! vamap-Debugger-Erweiterung in den Debugging-Tools für Windows verwenden, um dies zu überprüfen.

Hoffe das hilft Danke

Verwandte Fragen