79 Stimmen

Ist "Speicherplatzmangel" ein behebbarer Fehler?

Ich programmiere schon sehr lange, und die Programme, die ich sehe, wenn ihnen der Speicher ausgeht, versuchen aufzuräumen und sich zu beenden, d.h. sie scheitern mit Anstand. Ich kann mich nicht erinnern, wann ich das letzte Mal gesehen habe, dass ein Programm tatsächlich versucht hat, sich zu erholen und normal weiterzuarbeiten.

Ein so großer Teil der Verarbeitung hängt davon ab, dass Speicher erfolgreich zugewiesen werden kann, insbesondere in Sprachen mit Garbage-Collector, dass Fehler außerhalb des Speichers als nicht wiederherstellbar eingestuft werden sollten. (Zu den nicht wiederherstellbaren Fehlern gehören Dinge wie Stapelüberläufe.)

Welches zwingende Argument spricht dafür, dass es sich um einen anfechtbaren Fehler handelt?

1voto

Michael Borgwardt Punkte 334642

Vor allem in Garbage-Collecting-Umgebungen ist es wahrscheinlich, dass, wenn Sie den OutOfMemory-Fehler auf einer hohen Ebene der Anwendung abfangen, viel Material aus dem Anwendungsbereich herausgefallen ist und zurückgewonnen werden kann, um Ihnen Speicher zurückzugeben.

Im Falle einzelner übermäßiger Zuweisungen kann die App unter Umständen weiterhin einwandfrei funktionieren. Wenn Sie ein allmähliches Speicherleck haben, werden Sie natürlich wieder auf das Problem stoßen (wahrscheinlich eher früher als später), aber es ist immer noch eine gute Idee, der Anwendung eine Chance zu geben, sich zu beruhigen, nicht gespeicherte Änderungen im Falle einer GUI-Anwendung zu speichern usw.

1voto

Will Hartung Punkte 110997

Ja, OOM ist wiederherstellbar. Ein extremes Beispiel: Die Betriebssysteme Unix und Windows erholen sich in den meisten Fällen recht gut von OOM-Zuständen. Die Anwendungen fallen aus, aber das Betriebssystem überlebt (vorausgesetzt, es ist genügend Speicher vorhanden, damit das Betriebssystem überhaupt ordnungsgemäß starten kann).

Ich führe dieses Beispiel nur an, um zu zeigen, dass es möglich ist.

Das Problem des Umgangs mit OOM ist wirklich abhängig von Ihrem Programm und Ihrer Umgebung.

Zum Beispiel ist in vielen Fällen der Ort, an dem der OOM am wahrscheinlichsten auftritt, NICHT der beste Ort, um sich von einem OOM-Zustand zu erholen.

Nun könnte ein benutzerdefinierter Allokator möglicherweise als zentraler Punkt innerhalb des Codes fungieren, der einen OOM behandeln kann. Der Java-Allokator führt eine vollständige GC durch, bevor er eine OOM-Ausnahme auslöst.

Je "anwendungsbewusster" Ihr Allokator ist, desto besser eignet er sich als zentraler Handler und Recovery Agent für OOM. Wiederum mit Java ist der Allokator nicht besonders anwendungsbewusst.

Das ist der Punkt, an dem etwas wie Java leicht frustrierend ist. Sie können den Allokator nicht überschreiben. Während Sie also OOM-Ausnahmen in Ihrem eigenen Code abfangen können, gibt es keine Garantie dafür, dass eine Bibliothek, die Sie verwenden, eine OOM-Ausnahme richtig abfängt oder sogar richtig auslöst. Es ist trivial, eine Klasse zu erstellen, die durch eine OOM-Ausnahme für immer ruiniert ist, da ein Objekt auf null gesetzt wird und "das nie passiert", und es ist nie wiederherstellbar.

Also, ja, OOM ist wiederherstellbar, aber es kann sehr schwer sein, vor allem in modernen Umgebungen wie Java und es ist eine Fülle von 3rd-Party-Bibliotheken von unterschiedlicher Qualität.

1voto

geocar Punkte 8805

Das hängt davon ab, was Sie mit "zu wenig Speicher" meinen.

Wenn malloc() auf den meisten Systemen fehlschlägt, liegt das daran, dass Sie keinen Adressraum mehr haben.

Wenn der größte Teil des Speichers durch Cacheing oder durch mmap'd-Regionen belegt ist, können Sie vielleicht etwas davon zurückgewinnen, indem Sie den Cache freigeben oder das mmaping aufheben. Dies setzt jedoch voraus, dass Sie wissen, wofür Sie den Speicher verwenden - und wie Sie festgestellt haben, wissen das die meisten Programme nicht, oder es macht keinen Unterschied.

Wenn Sie die setrlimit() (vielleicht zum Schutz vor unvorhergesehenen Angriffen, oder vielleicht hat Root es Ihnen angetan), können Sie das Limit in Ihrem Error-Handler lockern. Ich mache das sehr häufig - wenn möglich, nachdem ich den Benutzer gefragt habe und das Ereignis protokolliert wurde.

Andererseits ist es etwas schwieriger, einen Stapelüberlauf abzufangen, und es ist nicht portabel. Ich habe eine posixartige Lösung für ECL und beschrieb eine Windows-Implementierung, falls Sie diesen Weg gehen wollen. Es wurde vor ein paar Monaten in ECL eingecheckt, aber ich kann die ursprünglichen Patches ausgraben, wenn Sie interessiert sind.

0voto

Friedrich Punkte 5828

Dies ist eine schwierige Frage. Auf den ersten Blick sieht es so aus, als ob es "Pech" bedeutet, keinen Speicher mehr zu haben, aber man muss auch sehen, dass man viele speicherbezogene Dinge loswerden kann, wenn man wirklich darauf besteht. Nehmen wir einfach die auf andere Weise kaputte Funktion strtok, die auf der einen Seite keine Probleme mit Speicher hat. Dann nehmen wir als Gegenstück g_string_split aus der Glib-Bibliothek, die wie fast alles in Glib- oder GObject-basierten Programmen stark von der Zuweisung von Speicher abhängt. Man kann definitiv sagen, dass in dynamischeren Sprachen die Speicherzuweisung viel mehr genutzt wird als in unflexibleren Sprachen, insbesondere C. Aber sehen wir uns die Alternativen an. Wenn Sie das Programm einfach beenden, wenn Ihnen der Speicher ausgeht, kann selbst sorgfältig entwickelter Code nicht mehr funktionieren. Aber wenn man einen behebbaren Fehler hat, kann man etwas dagegen tun. Das Argument, dass ein Fehler behebbar ist, bedeutet also, dass man diese Situation anders "handhaben" kann (z. B. indem man einen Speicherblock für Notfälle beiseite legt oder zu einem weniger speicherintensiven Programm degradiert).

Das ist also der zwingendste Grund. Wenn Sie eine Möglichkeit zur Wiederherstellung bieten, kann man die Wiederherstellung versuchen, wenn Sie nicht die Wahl haben, hängt alles davon ab, immer genug Speicher zu bekommen...

Mit freundlichen Grüßen

0voto

paercebal Punkte 78198

Das ist mir jetzt ein Rätsel.

Bei der Arbeit haben wir ein Bündel von Anwendungen, die zusammenarbeiten, und der Speicher wird knapp. Während das Problem entweder darin besteht, das Anwendungsbündel auf 64-Bit umzustellen (und damit über die 2-Go-Grenzen hinaus zu arbeiten, die wir bei einem normalen Win32-Betriebssystem haben) und/oder unsere Speichernutzung zu reduzieren, will mir das Problem "Wie erhole ich mich von einem OOM" nicht aus dem Kopf gehen.

Natürlich habe ich keine Lösung, aber ich spiele immer noch auf der Suche nach einer für C++ (vor allem wegen RAII und Ausnahmen).

Vielleicht sollte ein Prozess, der sich elegant wiederherstellen soll, seine Verarbeitung in atomare/rollback-fähige Tasks aufteilen (d.h. nur Funktionen/Methoden verwenden, die eine starke/nicht-auslösende Garantie bieten), wobei ein "Puffer/Speicherpool" für Wiederherstellungszwecke reserviert ist.

Sollte eine der Aufgaben fehlschlagen, würde C++ bad_alloc den Stack abwickeln und etwas Stack/Heap-Speicher durch RAII freigeben. Die Wiederherstellungsfunktion würde dann so viel wie möglich retten (und die Anfangsdaten der Aufgabe auf der Festplatte speichern, um sie bei einem späteren Versuch zu verwenden) und vielleicht die Aufgabendaten für einen späteren Versuch registrieren.

Ich glaube, dass die Verwendung von C++ strong/nothrow guanrantees einem Prozess helfen kann, unter Bedingungen mit wenig verfügbarem Speicher zu überleben, auch wenn es ähnlich wie Memory Swapping wäre (d.h. langsam, etwas reaktionslos, etc.), aber das ist natürlich nur Theorie. Ich muss mich erst schlauer machen, bevor ich versuche, dies zu simulieren (d.h. ein C++-Programm mit einem benutzerdefinierten New/Delete-Allokator mit begrenztem Speicher zu erstellen und dann zu versuchen, unter diesen stressigen Bedingungen zu arbeiten).

Na ja...

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X