C ++ / Windows: Wie melde ich eine Out-of-memory-Ausnahme (bad_alloc)?

8

Ich arbeite zur Zeit an einem ausnahmebasierten Fehlermeldesystem für Windows MSVC ++ (9.0) -Apps (zB Ausnahmestrukturen & amp; types / Vererbung, Callstack, Fehlerreporting & amp; Logging usw.).
< br> Meine Frage ist jetzt: Wie man & amp; einen Fehler wegen zu wenig Arbeitsspeicher protokollieren?

Wenn dieser Fehler auftritt, z.B. Als ein bad_alloc , das von new op geworfen wird, können viele "Features" nicht verfügbar sein, hauptsächlich was die weitere Speicherzuweisung betrifft. Normalerweise würde ich die Ausnahme an die Anwendung übergeben, wenn sie in eine Lib geworfen wurde, und dann Meldungsfelder und Fehlerprotokolldateien verwenden, um sie zu melden und zu protokollieren. Eine andere Möglichkeit (hauptsächlich für Dienste) ist die Verwendung des Windows-Ereignisprotokolls.
Das Hauptproblem, das ich habe, besteht darin, eine Fehlermeldung zu erstellen. Um einige Fehlerinformationen bereitzustellen, möchte ich eine statische Fehlermeldung definieren (kann ein String-Literal sein, besser ein Eintrag in einer Nachrichtendatei, dann FormatMessage verwenden) und einige Laufzeit-Informationen wie einen Aufruf-Stack einschließen > Die dafür notwendigen Funktionen / Methoden verwenden entweder

  • STL ( std::string, std::stringstream, std::ofstream )
  • CRT ( swprintf_s, fwrite )
  • oder Win32-API ( StackWalk64, MessageBox, FormatMessage, ReportEvent, WriteFile )

Abgesehen davon, dass sie auf dem MSDN dokumentiert sind, haben alle von ihnen mehr (Win32) oder weniger (STL) in Windows geschlossen, so dass ich nicht wirklich weiß, wie sie sich unter Problemen mit wenig Arbeitsspeicher verhalten Nur um zu beweisen, dass es Probleme geben könnte, schrieb ich eine triviale kleine App, die ein bad_alloc provoziert:

%Vor%

Lief zwei Instanzen ohne Debugger angeschlossen (in Release config, VS 2008), aber "nichts ist passiert", d. h. keine Fehlercodes von ReportEvent oder WriteFile, die ich intern in der Fehlerberichterstattung verwendet habe. Anschließend wurde eine Instanz mit und ohne Debugger gestartet, und sie konnten versuchen, ihre Fehler nacheinander mithilfe eines Haltepunkts in der Zeile ReportError zu melden. Das funktionierte gut für die Instanz mit dem angehängten Debugger (korrekt gemeldet und den Fehler protokolliert, sogar mit LocalAlloc ohne Probleme)! Aber taskman zeigte ein merkwürdiges Verhalten, bei dem viel Speicher freigesetzt wurde, bevor die App beendet wurde. Ich vermute, wenn die Ausnahme ausgelöst wird.


Bitte beachten Sie, dass es mehr als einen Prozess [edit] und mehr als einen Thread [/ edit] gibt, die viel Speicher verbrauchen. Daher ist das Freigeben von zuvor zugewiesenem Heap-Speicher keine sichere Lösung, um eine Umgebung mit wenig Speicher für den Prozess zu vermeiden der Fehler.

Vielen Dank im Voraus!

    
dyp 20.08.2010, 17:40
quelle

4 Antworten

2
  • Reservieren Sie die benötigten Puffer
  • vor
  • verknüpfen Sie statisch und verwenden Sie _beginthreadex anstelle von CreateThread (andernfalls können CRT-Funktionen fehlschlagen) - ODER - implementieren Sie die Zeichenfolge concat / i2a selbst
  • MessageBox verwenden (MB_SYSTEMMODAL | MB_OK) MSDN erwähnt dies für das Melden von OOM-Bedingungen (und einige MS-Blogger beschrieben dieses Verhalten wie beabsichtigt: das Nachrichtenfeld weist keinen Speicher zu.)

Die Protokollierung ist schwieriger, zumindest muss die Protokolldatei bereits geöffnet sein.

Wahrscheinlich am besten mit FILE_FLAG_NO_BUFFERING und FILE_FLAG_WRITE_THROUGH , um Pufferversuche zu vermeiden. Die erste erfordert, dass Schreibvorgänge und Ihre Speicherpuffer Sektoren-ausgerichtet sind (dh Sie müssen GetDiskFreeSpace abfragen, Ihren Puffer darauf ausrichten und nur auf "mehrere Sektorengrößen" -Dateioffsets und in Blöcke schreiben, die Vielfache der Sektorgröße sind. Ich bin mir nicht sicher, ob dies notwendig ist oder hilft, aber eine systemweite OOM, bei der jede Zuweisung fehlschlägt, ist schwer zu simulieren.

    
peterchen 23.08.2010, 19:24
quelle
3

"Vorbelegten Heap-Speicher freigeben ...". Das war genau das, was ich dir beim Lesen deiner Frage dachte. Aber ich denke du kannst es versuchen. Jeder Prozess hat seinen eigenen virtuellen Speicherplatz. Bei anderen Prozessen, die viel Arbeitsspeicher belegen, funktioniert dies möglicherweise noch, wenn der gesamte Computer funktioniert.

    
Alex F 20.08.2010 17:53
quelle
1
  

Beachten Sie, dass mehr als ein Prozess viel Arbeitsspeicher belegen kann. Daher ist das Freigeben von bereits zugewiesenem Heap-Speicher keine sichere Lösung, um eine Umgebung mit geringem Arbeitsspeicher für den Prozess zu vermeiden, der den Fehler melden möchte.

Unter Windows (und anderen modernen Betriebssystemen) hat jeder Prozess seinen eigenen Adressraum (auch Speicher genannt), der von jedem anderen laufenden Prozess getrennt ist. Und all das ist getrennt von dem wörtlichen RAM in der Maschine. Das Betriebssystem hat den Prozessadressraum vom physischen RAM entfernt virtualisiert.

Auf diese Weise kann Windows den von Prozessen verwendeten Speicher in die Auslagerungsdatei auf der Festplatte schieben, ohne dass diese Prozesse wissen, was passiert ist.

Dies ist auch, wie ein einzelner Prozess mehr Speicher reservieren kann, als der Rechner physischen RAM hat und trotzdem noch läuft. Zum Beispiel könnte ein Programm, das auf einer Maschine mit 512 MB RAM läuft, immer noch 1 GB Speicher reservieren. Windows könnte einfach nicht alles gleichzeitig im RAM behalten und ein Teil davon wäre in der Auslagerungsdatei. Aber das Programm würde es nicht wissen.

Wenn also ein Prozess Speicher zuweist, verursacht dies nicht, dass ein anderer Prozess weniger Arbeitsspeicher zur Verfügung hat. Jeder Prozess ist separat.

Jeder Prozess muss sich nur um sich selbst kümmern. Und so ist die Idee, einen vorher zugewiesenen Teil des Gedächtnisses zu befreien, tatsächlich sehr praktikabel.

    
TheUndeadFish 20.08.2010 18:26
quelle
0

Sie können keine CRT- oder MessageBox-Funktionen zum Behandeln von OOM verwenden, da sie möglicherweise, wie Sie beschreiben, Speicher benötigen. Die einzige wirklich sichere Sache, die Sie tun können, ist, ein Stück Speicher beim Start zuzuweisen Sie können Informationen in eine Datei oder eine Pipe schreiben und öffnen, dann WriteFile darauf, wenn Sie OOM out.

    
Paul Betts 20.08.2010 23:25
quelle