2014-04-22 12 views
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 Debugging von Crash-Dump-Dateien mit WinDbg, sehe ich, dass der größte Teil des Speichers tatsächlich reserviert und nicht verpflichtet ist. enter image description hereKann reservierten Speicher verursachen eine Out of Memory-Ausnahme

Wie man es von WinDbg Screenshot sehen kann, gibt es 2,5 Gb unklassifizierter Speichernutzung, und das meiste davon 2,1 Gb ist eigentlich reservierten Speicher (MEM_RESERVE). Ich habe Erfahrung, Crush-Dumps zu debuggen, aber dieses Szenario ist etwas Neues für mich. MEM_COMMIT ist OK verlassen - 564,270 Mb, verwalteten Heap der Größe ca. 82 Mb ist

enter image description here

Ich habe auch einheimische Haufen zu sehen, wenn es große Brocken von Daten erhalten sind, konnte aber nichts Verdächtiges dort finden entweder

enter image description here

Also meine Frage ist - ist es möglich, dass MEM_RESERVED in OOM Ausnahme führen könnte? 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 meine Post aktualisieren.

Antwort

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 auslösen, indem Sie diese Arrays zuweisen.

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

+0

danke für die Antwort, wissen Sie vielleicht, wie kann ich sehen, was diese riesige Speicher in WinDbg reserviert? – Michael

+0

Angenommen, der Speicher wird vom verwalteten Objekt verwendet, können Sie diese mit '! Dumpheap' und'! Do' überprüfen. Da jedoch die Ausgabe von '! Eeheap 'anzeigt, dass der gemanagte Heap klein ist, nehme ich an, dass etwas anderes diesen Speicher reserviert hat. –

+0

Könnten Sie bitte angeben, was sonst Speicher reservieren kann? Ich bin verwirrt, weil ich erwarten würde, dass "etwas" entweder auf verwaltetem Heap oder einer nativen Ressource auf nativen Heaps ist - keines von beiden verweist auf verdächtige Dinge. Was sonst könnte Speicher reservieren? Ich wäre mehr als froh, es sofort zu überprüfen. – Michael

3

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

Sie können, dass in C++ versuchen am einfachsten:

while(::VirtualAlloc(NULL, 65536, MEM_RESERVE, PAGE_READWRITE) != NULL); 
std::cout << "All memory reserved. Now check with tools." << std::endl; 

Wenn VirtualAlloc() NULL zurück, es könnte nicht mehr memoy zuordnen. In WinDbg wird dies zeigen

MEM_RESERVE 32307 7f6f2000 (1.991 Gb) 99.59% 99.56% 

jedoch VirtualAlloc() keine Zuteilung von Speicher auf dem Heap, so !heap in diesem Fall nicht sinnvoll ist, und zeigt nur die Standard-Prozess-Heap:

0:000> !heap 
Index Address Name  Debugging options enabled 
    1: 00440000 

Es ist die Andersherum: Der Heap-Manager verwendet VirtualAlloc(), um den Speicher abzurufen. Beachten Sie auch, dass .NET den Heap-Manager ebenfalls nicht 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 die gflags Einstellung Enable heap tagging by DLL sollte hilfreich sein, um die Quelle einer Heap-Zuordnung zu bestimmen. Meine Erwartung, dass der Befehl !heap -t einfach den Namen der DLL anzeigen würde, die den Speicher zugewiesen hat, wurde jedoch nicht erfüllt.

+0

danke für die Eingabe. Ich habe versucht, Heap-T-Befehl, aber es gab nichts nützliches. Ich versuche, in den nativen Speicher zu graben, um zu sehen, was ich dort finde. Jeder andere Vorschlag, etwas anderes zu überprüfen, ist sehr willkommen. – Michael