Kann reservierter Speicher eine Out of Memory-Ausnahme verursachen

8

Wir haben einen 32-Bit-Windows-Dienst, der Speicher verliert - OutOfMemory-Ausnahme wird ausgelöst. Es ist ausführbare .net 4.0-Datei auf Windows-Server 2003 ausgeführt. Beim Debuggen von Crash-Dump-Dateien mit WinDbg, sehe ich, dass der größte Teil des Speichers tatsächlich reserviert und nicht verpflichtet ist.

Wie Sie aus WinDbg Screenshot sehen können, gibt es 2.5 Gb nicht klassifizierten Speicherverbrauch, und die meisten davon 2.1 Gb ist eigentlich reservierter Speicher (MEM_RESERVE). Ich habe Erfahrung, Crush-Dumps zu debuggen, aber dieses Szenario ist etwas Neues für mich. MEM_COMMIT ist beendet OK - 564.270 Mb, verwaltete Heap-Größe ist ca. 82 Mb

Ich habe auch native Heaps überprüft, um zu sehen, ob große Datenmengen erhalten bleiben, aber dort auch nichts verdächtiges finden konnte

Meine Frage ist also - ist es möglich, dass MEM_RESERVED zu einer OOM-Ausnahme führt? Wenn ja, wie kann ich es debuggen, warum / wie viel Speicher wird reserviert? Wo sonst würden Sie suchen, um herauszufinden, was das Problem sein könnte?

Wenn weitere Informationen erforderlich sind, bitte fragen Sie danach, und ich werde meinen Beitrag aktualisieren.

    
Michael 22.04.2014, 19:25
quelle

2 Antworten

6

Ja, das Reservieren von Speicher kann OutOfMemoryException auslösen. Versuchen Sie, ein paar sehr große Byte-Arrays zuzuweisen. Der Speicher für diese wird nicht festgelegt, bis Sie in den Inhalt der Arrays schreiben. Sie können OOM jedoch einfach durch Zuweisen dieser Arrays auslösen.

Ich kenne die Implementierungsdetails nicht, aber da VirtualAlloc fehlschlägt, wenn eine Reservierungsanforderung nicht berücksichtigt werden kann, nehme ich an, dass die CLR dies in eine Ausnahme übersetzt. Ich sehe nicht, wie es eine fehlgeschlagene Reserveanforderung in etwas Nützliches verwandeln könnte, also ist eine Ausnahme eine vernünftige Wahl.

    
Brian Rasmussen 22.04.2014 19:37
quelle
3

OutOfMemoryException tritt auf, wenn das System nicht mehr virtuellen Speicher für Ihre Anwendung reservieren kann. Reservierter Speicher ist virtueller Speicher und berücksichtigt daher diese Grenze.

Das können Sie in C ++ am einfachsten ausprobieren:

%Vor%

Wenn VirtualAlloc () NULL zurückgibt, konnte nicht mehr Memoy zugewiesen werden. In WinDbg wird dies

anzeigen %Vor%

Allerdings reserviert VirtualAlloc () keinen Speicher im Heap, daher ist !heap in diesem Fall nicht nützlich und zeigt nur den Standard-Prozess-Heap:

%Vor%

Es ist umgekehrt: Der Heap-Manager verwendet VirtualAlloc (), um den Speicher zu erhalten. Beachten Sie außerdem, dass .NET auch nicht den Heap-Manager verwendet. Es reserviert auch Speicher direkt mit VirtualAlloc () und verwaltet es dann eigenständig. Also, weil Sie es in der Ausgabe von !heap sehen können, ist es kein .NET-Problem, es ist ein natives Speicherproblem.

In meinem naiven Verständnis der gflags Einstellung Aktivieren Sie Heap-Tagging von DLL sollte hilfreich sein, um die Quelle einer Heap-Zuordnung zu bestimmen. Meine Erwartung, dass der Befehl !heap -t nur den Namen der DLL anzeigen würde, die den Speicher zugewiesen hat, wurde jedoch nicht erfüllt.

    
Thomas Weller 23.04.2014 06:51
quelle