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?

5voto

slim Punkte 37932

Ich denke, dass es wie bei vielen Dingen eine Kosten-Nutzen-Analyse ist. Sie kann Programm bei dem Versuch, sich von einem malloc()-Fehler zu erholen - auch wenn es schwierig sein könnte (Ihr Handler sollte besser nicht in die gleiche Speicherknappheit verfallen, mit der er eigentlich umgehen soll).

Sie haben bereits festgestellt, dass der häufigste Fall darin besteht, sich zu bereinigen und elegant zu scheitern. In diesem Fall wurde entschieden, dass die Kosten für einen ordnungsgemäßen Abbruch geringer sind als die Kombination aus Entwicklungskosten und Leistungskosten für die Wiederherstellung.

Sicher fallen Ihnen eigene Beispiele für Situationen ein, in denen die Beendigung des Programms eine sehr teure Option ist (lebenserhaltende Maschinen, Raumschiffsteuerung, langwierige und zeitkritische Finanzberechnungen usw.) - obwohl die erste Verteidigungslinie natürlich darin besteht, sicherzustellen, dass das Programm einen vorhersehbaren Speicherverbrauch hat und dass die Umgebung diesen liefern kann.

4voto

Dennis C Punkte 23918

Er ist nur dann wiederherstellbar, wenn man ihn auffängt und richtig behandelt.

In denselben Fällen wurde zum Beispiel versucht, viel Speicher zuzuweisen. Es ist ziemlich vorhersehbar und Sie können es sehr gut behandeln.

In vielen Fällen in Multi-Thread-Anwendungen kann OOE jedoch auch in Hintergrund-Threads auftreten (einschließlich der von System- und Drittanbieter-Bibliotheken erstellten). Es ist fast unmöglich, dies vorherzusagen, und Sie können den Zustand aller Ihrer Threads möglicherweise nicht wiederherstellen.

3voto

Nein. Ein Out-of-Memory-Fehler der GC sollte im Allgemeinen nicht innerhalb des aktuellen Threads wiederherstellbar sein. (Die Erstellung und Beendigung von Threads (Benutzer oder Kernel) sollte jedoch unterstützt werden)

Zu den Gegenbeispielen: Ich arbeite derzeit an einem Projekt in der Programmiersprache D, das die CUDA-Plattform von NVIDIA für GPU-Computing nutzt. Anstatt den GPU-Speicher manuell zu verwalten, habe ich Proxy-Objekte erstellt, um die GC von D zu nutzen. Wenn die GPU also einen Fehler wegen Speichermangels meldet, führe ich ein vollständiges Collect aus und löse nur dann eine Ausnahme aus, wenn es ein zweites Mal fehlschlägt. Aber das ist nicht wirklich ein Beispiel für die Wiederherstellung von Speicherplatzmangel, sondern eher für die GC-Integration. Die anderen Beispiele für die Wiederherstellung (Caches, freie Listen, Stacks/Hashes ohne automatisches Schrumpfen usw.) sind alles Strukturen, die ihre eigenen Methoden zum Sammeln/Verdichten von Speicher haben, die von der GC getrennt sind und in der Regel nicht lokal zur zuweisenden Funktion sind. Man könnte also etwas wie das Folgende implementieren:

T new2(T)( lazy T old_new ) {
    T obj;
    try{
        obj = old_new;
    }catch(OutOfMemoryException oome) {
        foreach(compact; Global_List_Of_Delegates_From_Compatible_Objects)
            compact();
        obj = old_new;
    }
    return obj;
}

Das ist ein gutes Argument für das Hinzufügen von Unterstützung für die Registrierung/Deregistrierung von selbstsammelnden/kompaktierenden Objekten zu Garbage Collectors im Allgemeinen.

2voto

Keith Thompson Punkte 240701

Die Frage ist als "sprachunabhängig" gekennzeichnet, aber es ist schwierig, sie zu beantworten, ohne die Sprache und/oder das zugrunde liegende System zu berücksichtigen. (Ich sehe mehrere andere Hadns

Wenn die Speicherzuteilung implizit erfolgt und es keinen Mechanismus gibt, um festzustellen, ob eine bestimmte Zuteilung erfolgreich war oder nicht, kann es schwierig oder unmöglich sein, einen Zustand zu überwinden, in dem kein Speicher mehr vorhanden ist.

Wenn Sie zum Beispiel eine Funktion aufrufen, die versucht, ein großes Array zuzuordnen, definieren die meisten Sprachen einfach nicht das Verhalten, wenn das Array nicht zugeordnet werden kann. (In Ada führt dies zu einer Storage_Error Ausnahme, zumindest im Prinzip, und es sollte möglich sein, dies zu handhaben).

Andererseits, wenn Sie einen Mechanismus haben, der versucht, Speicher zuzuweisen und in der Lage ist, einen Fehler zu melden (wie C's malloc() oder C++'s new ), dann ist es sicherlich möglich, sich von diesem Misserfolg zu erholen. Zumindest in den Fällen von malloc() y new Eine fehlgeschlagene Zuweisung bewirkt nichts anderes als die Meldung eines Fehlers (sie beschädigt z. B. keine internen Datenstrukturen).

Ob der Versuch einer Wiederherstellung sinnvoll ist, hängt von der Anwendung ab. Wenn die Anwendung nach einem Zuweisungsfehler einfach nicht mehr erfolgreich sein kann, sollte sie alle möglichen Bereinigungen vornehmen und den Vorgang beenden. Wenn der Zuweisungsfehler jedoch nur bedeutet, dass eine bestimmte Aufgabe nicht ausgeführt werden kann, oder wenn die Aufgabe auch mit weniger Speicher langsamer ausgeführt werden kann, dann ist es sinnvoll, den Betrieb fortzusetzen.

Ein konkretes Beispiel: Angenommen, ich verwende einen Texteditor. Wenn ich versuche, eine Operation im Editor auszuführen, die viel Speicherplatz benötigt, und diese Operation nicht ausgeführt werden kann, möchte ich, dass der Editor mir mitteilt, dass er nicht tun kann, was ich verlangt habe und mich weiter bearbeiten lassen . Eine Beendigung, ohne meine Arbeit zu speichern, wäre eine inakzeptable Reaktion. Meine Arbeit zu speichern und abzubrechen wäre besser, ist aber immer noch unnötig benutzerfeindlich.

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.

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