Ist "Nicht genügend Speicher" ein behebbarer Fehler?


74

Ich habe lange programmiert, und die Programme, die ich sehe, wenn sie keinen Speicher mehr haben, versuchen zu bereinigen und zu beenden, dh sie schlagen ordnungsgemäß fehl. Ich kann mich nicht erinnern, wann ich das letzte Mal einen Versuch gesehen habe, mich zu erholen und normal weiter zu arbeiten.

So viel Verarbeitung hängt davon ab, dass Speicher erfolgreich zugewiesen werden kann, insbesondere in Sprachen, in denen Müll gesammelt wird. Es scheint, dass Fehler aufgrund von Speichermangel als nicht behebbar eingestuft werden sollten. (Nicht behebbare Fehler umfassen Dinge wie Stapelüberläufe.)

Was ist das überzeugende Argument dafür, dass es sich um einen behebbaren Fehler handelt?


Entschuldigung, wenn der obige Kommentar unhöflich war. Aber zum Beispiel können Java-GUI-Apps OutOfMemoryError ziemlich gut verarbeiten (ich bin kein großer Java-Fan, ich nehme nur meine Erfahrung zur Kenntnis) - beendet wird zB nur die Anfrage, die aus einer Einzelbenutzeraktion stammt.
KarolDepka

Manchmal ist es auch gut, einen einzelnen Thread sterben zu lassen, aber den Rest des Programms laufen zu lassen - das kommt manchmal natürlich vor.
KarolDepka

Außerdem kann der Fehler manchmal darin bestehen, nur die Behandlung eines einzelnen Ereignisses zu sabotieren (wie z. B. in einer GUI-Ereignisversandschleife / einem Thread).
KarolDepka

Hier ist eine weitere Diskussion von Walter Bright, warum OOM nicht wiederherstellbar ist
Alexander Malakhov

Antworten:


36

Es hängt wirklich davon ab, was Sie bauen.

Es ist nicht völlig unvernünftig, dass ein Webserver ein Anforderungs- / Antwortpaar nicht besteht, aber dann weiter nach weiteren Anforderungen sucht. Sie müssten jedoch sicher sein, dass der einzelne Fehler keine nachteiligen Auswirkungen auf den globalen Zustand hatte - das wäre das Knifflige. Angesichts der Tatsache, dass ein Fehler in den meisten verwalteten Umgebungen (z. B. .NET und Java) eine Ausnahme verursacht, vermute ich, dass die Ausnahme, wenn sie im "Benutzercode" behandelt wird, für zukünftige Anforderungen wiederhergestellt werden kann - z. B. wenn eine Anforderung versucht hat, 10 GB Speicher zuzuweisen und fehlgeschlagen, das sollte dem Rest des Systems nicht schaden. Wenn dem System jedoch der Speicherplatz ausgeht, während versucht wird, die Anforderung an den Benutzercode weiterzuleiten, kann dies unangenehmer sein.


39
Whoa ... Jon Skeet beantwortet eine Frage von Walter Bright. Ich habe gerade einen Schauer über meinen Rücken bekommen (oder vielleicht lag das daran, dass es hier 62 ° F ist).
Michael Myers

17

In einer Bibliothek möchten Sie eine Datei effizient kopieren. Wenn Sie dies tun, werden Sie normalerweise feststellen, dass das Kopieren mit einer kleinen Anzahl großer Blöcke viel effektiver ist als das Kopieren vieler kleinerer Blöcke (beispielsweise ist das Kopieren einer 15-MB-Datei durch Kopieren von 15 1-MB-Blöcken schneller als das Kopieren von 15'000 1K Stücke).

Der Code funktioniert jedoch mit jeder Blockgröße. Wenn Sie also für ein System entwerfen, in dem viele Dateien kopiert werden, ist es mit 1-MB-Chunks möglicherweise schneller. Es ist jedoch ratsam, OutOfMemoryError abzufangen und die Chunk-Größe zu reduzieren, bis Sie erfolgreich sind.

Ein anderer Ort ist ein Cache für Objekte, die in einer Datenbank gespeichert sind. Sie möchten so viele Objekte wie möglich im Cache behalten, aber den Rest der Anwendung nicht stören. Da diese Objekte neu erstellt werden können, ist es eine clevere Möglichkeit, Speicherplatz zu sparen, um den Cache an einen Handler für nicht genügend Speicher anzuhängen und Einträge zu löschen, bis der Rest der App wieder genügend Platz zum Atmen hat.

Schließlich möchten Sie zur Bildbearbeitung so viel Bild wie möglich in den Speicher laden. Auch hier können Sie mit einem OOM-Handler dies implementieren, ohne vorher zu wissen, wie viel Speicher der Benutzer oder das Betriebssystem Ihrem Code gewähren wird.

[BEARBEITEN] Beachten Sie, dass ich hier unter der Annahme arbeite, dass Sie der Anwendung eine feste Speichermenge zugewiesen haben und diese Menge kleiner ist als der insgesamt verfügbare Speicher ohne Swap-Speicherplatz. Wenn Sie so viel Speicher zuweisen können, dass ein Teil davon ausgetauscht werden muss, sind einige meiner Kommentare nicht mehr sinnvoll.


7
Auf einem System mit virtuellem Speicher bedeutet das Prüfen, wie viel Sie zuweisen können, dass Sie Speicher zuweisen, der auf die Festplatte ausgelagert wird. Dies ist eine Pessimierung für einen Festplattenpuffer.
Walter Bright

1
Datenpunkt zu Ihrer Verteidigung: uClibc verfügt über einen internen statischen Puffer von ca. 8 Byte für Datei-E / A, wenn kein Speicher mehr dynamisch zugewiesen werden muss.
Prof. Falken

9

Benutzer von MATLAB haben ständig keinen Speicher mehr, wenn sie mit großen Arrays rechnen. Wenn beispielsweise die Variable x in den Speicher passt und "x + 1" ausgeführt wird, weist MATLAB dem Ergebnis Speicherplatz zu und füllt es dann aus. Wenn die Zuordnung fehlschlägt, können MATLAB-Fehler auftreten und der Benutzer kann etwas anderes ausprobieren. Es wäre eine Katastrophe, wenn MATLAB bei jedem Auftreten dieses Anwendungsfalls beendet würde.


8

OOM sollte wiederherstellbar sein, da das Herunterfahren nicht die einzige Strategie zur Wiederherstellung von OOM ist.

Es gibt tatsächlich eine ziemlich standardmäßige Lösung für das OOM-Problem auf Anwendungsebene. Bestimmen Sie im Rahmen Ihres Anwendungsdesigns eine sichere Mindestmenge an Speicher, die zur Wiederherstellung nach einem Speichermangel erforderlich ist. (ZB der Speicher, der zum automatischen Speichern von Dokumenten, Aufrufen von Warndialogen und Protokollieren von Daten zum Herunterfahren erforderlich ist).

Weisen Sie zu Beginn Ihrer Anwendung oder zu Beginn eines kritischen Blocks diese Speichermenge vorab zu. Wenn Sie feststellen, dass nicht genügend Speicher vorhanden ist, geben Sie Ihren Schutzspeicher frei und führen Sie eine Wiederherstellung durch. Die Strategie kann immer noch scheitern, aber im Großen und Ganzen gibt es ein gutes Preis-Leistungs-Verhältnis.

Beachten Sie, dass die Anwendung nicht heruntergefahren werden muss. Es kann ein modales Dialogfeld angezeigt werden, bis die OOM-Bedingung behoben wurde.

Ich bin nicht 100% sicher, aber ich bin mir ziemlich sicher, dass ' Code Complete ' (erforderliche Lektüre für jeden seriösen Softwareentwickler) dies abdeckt.

PS Sie können Ihr Anwendungsframework erweitern, um diese Strategie zu unterstützen. Implementieren Sie eine solche Richtlinie jedoch nicht in einer Bibliothek (gute Bibliotheken treffen keine globalen Entscheidungen ohne Zustimmung einer Anwendung).


Dies wird in Code Complete erwähnt. Die Technik wird "Fallschirm" genannt, wenn ich mich richtig erinnere.
Jason Baker

Leider kann dies in Java nicht zuverlässig durchgeführt werden, da die JVM jederzeit OOM auslösen darf , nicht nur dort, wo Sie eine haben new. Wenn Sie also ein OOM abfangen, könnte es an einer Stelle ausgelöst worden sein, die Ihr Programm in einem inkonsistenten Zustand belassen hat. Siehe stackoverflow.com/questions/8728866/…
Raedwald

5

Ich denke, dass es wie viele andere Dinge eine Kosten-Nutzen-Analyse ist. Sie können einen Wiederherstellungsversuch nach einem malloc () - Fehler programmieren - obwohl dies schwierig sein kann (Ihr Handler sollte besser nicht den gleichen Speichermangel erleiden, mit dem er sich befassen soll).

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

Ich bin sicher, Sie können sich Ihre eigenen Beispiele für Situationen vorstellen, in denen das Beenden des Programms eine sehr teure Option ist (lebenserhaltende Maschine, Raumschiffkontrolle, langfristige und zeitkritische Finanzberechnung usw.) - obwohl dies die erste Verteidigungslinie ist Natürlich, um sicherzustellen, dass das Programm eine vorhersehbare Speichernutzung hat und dass die Umgebung dies bereitstellen kann.


1
Wenn das Beenden des Programms aufgrund von Speicherfehlern undenkbar ist, haben Sie ein sehr ernstes Designproblem in der Hand, das möglicherweise eine benutzerdefinierte Lösung erfordert (z. B. statische Zuordnung aller Daten oder Vorbelegung).
Walter Bright

Nun ja, aber es gibt Grade von Undenkbarem und es gibt Grade von Anstrengung, die Sie in Wiederherstellungsstrategien stecken können. Ich bin mir sicher, dass dies eine sehr häufige Überlegung ist, wenn Sie beispielsweise für Spielekonsolen entwickeln.
schlank

Eine triviale Strategie, die für einige Anwendungen ausreichen könnte: void * my_malloc (size_t nbytes) {for (int i = 0; i <MALLOC_RETRIES) {void * p = malloc (nbytes); if (null! = p) return p; Schlaf (5); }}
schlank

5

Ich arbeite an einem System, das Speicher für den E / A-Cache zuweist, um die Leistung zu steigern. Beim Erkennen von OOM wird ein Teil davon zurückgenommen, sodass die Geschäftslogik fortgesetzt werden kann, selbst wenn dies weniger E / A-Cache und eine etwas geringere Schreibleistung bedeutet.

Ich habe auch mit eingebetteten Java-Anwendungen gearbeitet, die versuchten, OOM zu verwalten, indem sie die Speicherbereinigung erzwangen und optional einige unkritische Objekte wie vorab abgerufene oder zwischengespeicherte Daten freigaben.

Die Hauptprobleme bei der OOM-Handhabung sind:

1) an dem Ort, an dem es passiert ist, erneut versuchen zu können oder von einem höheren Punkt aus zurückrollen und erneut versuchen können. Die meisten zeitgenössischen Programme verlassen sich zu sehr auf die Sprache, um sie zu werfen, und schaffen es nicht wirklich, wo sie landen und wie sie die Operation erneut versuchen können. Normalerweise geht der Kontext der Operation verloren, wenn er nicht beibehalten werden soll

2) in der Lage sein, tatsächlich etwas Speicher freizugeben. Dies bedeutet eine Art Ressourcenmanager, der weiß, welche Objekte kritisch sind und welche nicht, und das System kann die freigegebenen Objekte erneut anfordern, wenn und wenn sie später kritisch werden

Ein weiteres wichtiges Problem ist das Zurücksetzen, ohne eine weitere OOM-Situation auszulösen. Dies ist in höheren Sprachen schwer zu kontrollieren.

Außerdem muss sich das zugrunde liegende Betriebssystem in Bezug auf OOM vorhersehbar verhalten. Linux zum Beispiel wird dies nicht tun, wenn Speicher-Overcommit aktiviert ist. Viele Swap-fähige Systeme sterben früher ab, als das OOM an die betreffende Anwendung zu melden.

Und es gibt den Fall, dass nicht Ihr Prozess die Situation verursacht hat. Das Freigeben von Speicher hilft also nicht, wenn der fehlerhafte Prozess weiterhin ausläuft.

Aus diesem Grund sind es oft die großen und eingebetteten Systeme, die diese Techniken anwenden, da sie die Kontrolle über Betriebssystem und Speicher haben, um sie zu ermöglichen, und die Disziplin / Motivation, sie zu implementieren.


Sie sehen die Wiederherstellung von OOM also als etwas, das Sie mit einer benutzerdefinierten Speicherzuweisungsmethode tun würden, nicht mit einer Standardbibliotheksmethode?
Walter Bright

Sie können dies auch mit der Standardmethode tun, wenn Sie wissen, was freigegeben werden soll, und dies ohne neuen Speicher. Wir haben es mit dem Standard-Java-Speichermanager mit einigem Erfolg gemacht.
n-Alexander

4

Es kann nur wiederhergestellt werden, wenn Sie es fangen und richtig damit umgehen.

In denselben Fällen wurde beispielsweise bei einer Anforderung versucht, viel Speicher zuzuweisen. Es ist ziemlich vorhersehbar und man kann sehr sehr gut damit umgehen.

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


3

Nein. Ein Speicherfehler des GC sollte im Allgemeinen nicht innerhalb des aktuellen Threads behoben werden können. (Die Erstellung und Beendigung eines wiederherstellbaren Threads (Benutzer oder Kernel) sollte jedoch unterstützt werden.)

Zu den Gegenbeispielen: Ich arbeite derzeit an einem D-Programmiersprachenprojekt, das die CUDA-Plattform von NVIDIA für GPU-Computing verwendet. Anstatt den GPU-Speicher manuell zu verwalten, habe ich Proxy-Objekte erstellt, um den GC des D zu nutzen. Wenn die GPU einen Speicherfehler zurückgibt, führe ich eine vollständige Erfassung durch und löse nur dann eine Ausnahme aus, wenn sie ein zweites Mal fehlschlägt. Dies ist jedoch kein Beispiel für eine Wiederherstellung ohne Speicherplatz, sondern eher für die GC-Integration. Die anderen Beispiele für die Wiederherstellung (Caches, freie Listen, Stapel / Hashes ohne automatisches Verkleinern usw.) sind alle Strukturen, die ihre eigenen Methoden zum Sammeln / Komprimieren von Speicher haben, die vom GC getrennt sind und in der Regel nicht lokal für die Zuweisung sind Funktion. Die Leute könnten also Folgendes 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;
}

Dies ist ein anständiges Argument für das Hinzufügen von Unterstützung für das Registrieren / Aufheben der Registrierung selbstsammelnder / komprimierender Objekte bei Garbage Collectors im Allgemeinen.


1

Im allgemeinen Fall ist es nicht wiederherstellbar.

Wenn Ihr System jedoch eine Form des dynamischen Caching enthält, kann ein Handler mit nicht genügend Speicher häufig die ältesten Elemente im Cache (oder sogar den gesamten Cache) sichern.

Natürlich müssen Sie sicherstellen, dass für den "Dumping" -Prozess keine neuen Speicherzuordnungen erforderlich sind :) Außerdem kann es schwierig sein, die fehlgeschlagene Zuweisung wiederherzustellen, es sei denn, Sie können Ihren Cache-Dumping-Code direkt am Allokator einstecken Ebene, so dass der Fehler nicht an den Anrufer weitergegeben wird.


Wäre dies nicht allgemeiner und besser zu handhaben, wenn einige Zuordnungen als "schwach" markiert werden könnten, was bedeutet, dass der Zuweiser sie freigeben kann, wenn er mehr Speicher benötigt?
Walter Bright

möglicherweise, obwohl Sie wahrscheinlich einen anderen Namen benötigen würden, da normalerweise "schwach" eher für Referenzen als für Zuordnungen verwendet wird und eine Überladung auf diese Weise wahrscheinlich zu Verwirrung führen würde. Und mit Ihrem Ansatz zu gehen könnte nicht so selektiv sein wie Cache-Bereinigung (oder andere OOM-Handler)
Mike G.

1

Es hängt davon ab, was Sie unter Speichermangel verstehen.

Wenn malloc()dies auf den meisten Systemen fehlschlägt, liegt dies daran, dass Ihnen der Adressraum ausgeht.

Wenn der größte Teil dieses Speichers durch Cacheing oder durch mmap-Regionen belegt wird, können Sie möglicherweise einen Teil davon zurückgewinnen, indem Sie Ihren Cache freigeben oder die Zuordnung aufheben. Dies setzt jedoch voraus, dass Sie wissen, wofür Sie diesen Speicher verwenden - und wie Sie bemerkt haben, tun dies entweder die meisten Programme nicht oder es macht keinen Unterschied.

Wenn Sie sich setrlimit()selbst verwendet haben (um sich vielleicht vor unvorhergesehenen Angriffen zu schützen, oder wenn Root es Ihnen angetan hat), können Sie das Limit in Ihrem Fehlerbehandler lockern. Ich mache das sehr häufig - nachdem ich den Benutzer nach Möglichkeit dazu aufgefordert und das Ereignis protokolliert habe.

Andererseits ist das Auffangen eines Stapelüberlaufs etwas schwieriger und nicht portabel. Ich habe eine posixische Lösung für ECL geschrieben und eine Windows-Implementierung beschrieben, wenn Sie diesen Weg gehen. Es wurde vor einigen Monaten in ECL eingecheckt, aber ich kann die Original-Patches ausgraben, wenn Sie interessiert sind.


1

Insbesondere in Umgebungen, in denen Müll gesammelt wurde, ist es wahrscheinlich, dass, wenn Sie den OutOfMemory-Fehler auf einer hohen Ebene der Anwendung abfangen, viele Dinge außerhalb des Gültigkeitsbereichs liegen und zurückgefordert werden können, um Ihnen Speicherplatz zurückzugeben.

Bei einzelnen übermäßigen Zuweisungen kann die App möglicherweise fehlerfrei weiterarbeiten. Wenn Sie einen allmählichen Speicherverlust haben, werden Sie natürlich erneut auf das Problem stoßen (eher früher als später), aber es ist immer noch eine gute Idee, der App die Möglichkeit zu geben, ordnungsgemäß herunterzufahren und nicht gespeicherte Änderungen in der zu speichern Fall einer GUI-App usw.


1

Ja, OOM kann wiederhergestellt werden. Als extremes Beispiel erholen sich die Unix- und Windows-Betriebssysteme die meiste Zeit recht gut von den OOM-Bedingungen. Die Anwendungen schlagen fehl, aber das Betriebssystem überlebt (vorausgesetzt, es ist genügend Speicher vorhanden, damit das Betriebssystem überhaupt ordnungsgemäß gestartet werden kann).

Ich zitiere dieses Beispiel nur, um zu zeigen, dass es möglich ist.

Das Problem des Umgangs mit OOM hängt wirklich von Ihrem Programm und Ihrer Umgebung ab.

In vielen Fällen ist beispielsweise der Ort, an dem das OOM am wahrscheinlichsten auftritt, NICHT der beste Ort, um sich tatsächlich von einem OOM-Status zu erholen.

Jetzt könnte ein benutzerdefinierter Allokator möglicherweise als zentraler Punkt innerhalb des Codes fungieren, der eine OOM verarbeiten kann. Der Java-Allokator führt eine vollständige GC durch, bevor tatsächlich eine OOM-Ausnahme ausgelöst wird.

Je "anwendungsbewusster" Ihr Allokator ist, desto besser eignet er sich als zentraler Handler und Wiederherstellungsagent für OOM. Bei erneuter Verwendung von Java ist der Allokator nicht besonders anwendungsorientiert.

Hier ist so etwas wie Java leicht frustrierend. Sie können den Allokator nicht überschreiben. Während Sie OOM-Ausnahmen in Ihrem eigenen Code abfangen könnten, gibt es nichts, was besagt, dass eine von Ihnen verwendete Bibliothek eine OOM-Ausnahme ordnungsgemäß abfängt oder sogar ordnungsgemäß auslöst. Es ist trivial, eine Klasse zu erstellen, die durch eine OOM-Ausnahme für immer ruiniert wird, da ein Objekt auf null gesetzt wird und "das nie passiert" und niemals wiederherstellbar ist.

Ja, OOM kann wiederhergestellt werden, aber es kann SEHR schwierig sein, insbesondere in modernen Umgebungen wie Java und einer Vielzahl von Bibliotheken von Drittanbietern unterschiedlicher Qualität.


1

Die Frage ist mit "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 toher hadns

Wenn die Speicherzuweisung implizit ist und kein Mechanismus vorhanden ist, um festzustellen, ob eine bestimmte Zuweisung erfolgreich war oder nicht, kann die Wiederherstellung nach einem Speichermangel schwierig oder unmöglich sein.

Wenn Sie beispielsweise eine Funktion aufrufen, die versucht, ein großes Array zuzuweisen, definieren die meisten Sprachen das Verhalten einfach nicht, wenn das Array nicht zugewiesen werden kann. (In Ada wirft dies Storage_Errorzumindest im Prinzip eine Ausnahme auf, und es sollte möglich sein, damit umzugehen.)

Wenn Sie jedoch über einen Mechanismus verfügen, der versucht, Speicher zuzuweisen, und in der Lage sind, einen Fehler zu melden (z. B. C malloc()oder C ++ new), ist es durchaus möglich, diesen Fehler zu beheben. Zumindest in den Fällen von malloc()und newführt eine fehlgeschlagene Zuordnung nur zu einem Berichtsfehler (sie beschädigt beispielsweise keine internen Datenstrukturen).

Ob es sinnvoll ist, eine Wiederherstellung zu versuchen, hängt von der Anwendung ab. Wenn die Anwendung nach einem Zuordnungsfehler einfach nicht erfolgreich sein kann, sollte sie die Bereinigung durchführen und beenden. Wenn der Zuordnungsfehler jedoch nur bedeutet, dass eine bestimmte Aufgabe nicht ausgeführt werden kann oder wenn die Aufgabe mit weniger Speicher noch langsamer ausgeführt werden kann, 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 Speicher benötigt, und diese Operation nicht ausgeführt werden kann, möchte ich, dass der Editor mir mitteilt, dass er nicht das tun kann, was ich verlangt habe, und dass ich weiter bearbeite . Das Beenden ohne Speichern meiner Arbeit wäre eine inakzeptable Antwort. Das Speichern und Beenden meiner Arbeit wäre besser, ist aber immer noch unnötig benutzerfeindlich.


0

Dies ist eine schwierige Frage. Auf den ersten Blick scheint es "kein Glück" zu haben, kein Gedächtnis mehr zu haben, aber Sie müssen auch sehen, dass man viele Dinge im Zusammenhang mit dem Gedächtnis loswerden kann, wenn man wirklich darauf besteht. Nehmen wir einfach die auf andere Weise kaputte Funktion strtok, die einerseits keine Probleme mit Speichermaterial hat. Nehmen Sie dann g_string_split als Gegenstück aus der Glib-Bibliothek, die stark von der Speicherzuweisung abhängt, wie fast alles in glib- oder GObject-basierten Programmen. Man kann definitiv sagen, dass in dynamischeren Sprachen die Speicherzuweisung viel häufiger verwendet wird als in unflexibleren Sprachen, insbesondere C. Aber lassen Sie uns die Alternativen sehen. Wenn Sie das Programm nur beenden, wenn Ihnen der Speicher ausgeht, funktioniert möglicherweise auch sorgfältig entwickelter Code nicht mehr. Wenn Sie jedoch einen behebbaren Fehler haben, können Sie etwas dagegen tun. Also das Argument,

Der überzeugendste Grund ist also. Wenn Sie eine Möglichkeit zur Wiederherstellung bereitstellen, können Sie die Wiederherstellung versuchen. Wenn Sie nicht die Wahl haben, hängt alles davon ab, immer genügend Speicher zu erhalten ...

Grüße


0

Es verwirrt mich jetzt nur.

Bei der Arbeit arbeiten mehrere Anwendungen zusammen, und der Arbeitsspeicher geht zur Neige. Während das Problem entweder darin besteht, das Anwendungspaket auf 64-Bit umzustellen (und somit in der Lage zu sein, über die 2-Go-Grenzen hinaus zu arbeiten, die wir unter einem normalen Win32-Betriebssystem haben) und / oder die Speichernutzung zu reduzieren, ist dieses Problem von "How to von einem OOM erholen "wird meinen Kopf nicht verlassen.

Natürlich habe ich keine Lösung, spiele aber immer noch nach einer für C ++ (hauptsächlich wegen RAII und Ausnahmen).

Möglicherweise sollte ein Prozess, der ordnungsgemäß wiederhergestellt werden soll, seine Verarbeitung in atomaren / Rollback-fähigen Aufgaben unterbrechen (dh nur Funktionen / Methoden verwenden, die eine starke / keine Ausnahme-Garantie bieten), wobei ein "Puffer / Speicherpool" für Wiederherstellungszwecke reserviert ist.

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

Ich glaube, dass die Verwendung von C ++ Strong / Nothrow-Garantien dazu beitragen kann, dass ein Prozess unter Bedingungen mit wenig verfügbarem Speicher überlebt, selbst wenn es sich um einen ähnlichen Speicheraustausch handelt (dh langsam, etwas nicht reagierend usw.), aber dies ist natürlich der Fall nur Theorie. Ich muss mich nur mit dem Thema befassen, bevor ich versuche, dies zu simulieren (dh ein C ++ - Programm mit einem benutzerdefinierten Neu- / Lösch-Allokator mit begrenztem Speicher zu erstellen und dann zu versuchen, unter diesen stressigen Bedingungen etwas zu arbeiten).

Gut...


0

Nicht genügend Speicher bedeutet normalerweise, dass Sie alles beenden müssen, was Sie getan haben. Wenn Sie jedoch bei der Bereinigung vorsichtig sind, kann das Programm selbst betriebsbereit bleiben und auf andere Anforderungen reagieren. Es ist besser, wenn ein Programm "Entschuldigung, nicht genug Speicher" sagt, als "Entschuldigung, nicht genügend Speicher, wird heruntergefahren".


0

Zu wenig Speicher kann entweder durch freie Speicherentleerung oder durch den Versuch verursacht werden, einen unangemessen großen Block (wie einen Gig) zuzuweisen. In Fällen von "Erschöpfung" ist der Speichermangel für das System global und wirkt sich normalerweise auf andere Anwendungen und Systemdienste aus. Das gesamte System kann instabil werden. Es ist daher ratsam, es zu vergessen und neu zu starten. In Fällen von "unangemessen großem Block" tritt tatsächlich kein Mangel auf und es ist sicher, fortzufahren. Das Problem ist, dass Sie nicht automatisch erkennen können, in welchem ​​Fall Sie sich befinden. Daher ist es sicherer, den Fehler nicht behebbar zu machen und eine Problemumgehung für jeden Fall zu finden, in dem dieser Fehler auftritt. Lassen Sie Ihr Programm weniger Speicher verwenden oder beheben Sie es in einigen Fällen einfach Fehler im Code, der die Speicherzuordnung aufruft.


0

Hier gibt es bereits viele gute Antworten. Aber ich möchte mit einer anderen Perspektive beitragen.

Die Erschöpfung nahezu aller wiederverwendbaren Ressourcen sollte im Allgemeinen wiederherstellbar sein. Der Grund dafür ist, dass jeder Teil eines Programms im Grunde ein Unterprogramm ist. Nur weil ein Sub zu diesem Zeitpunkt nicht vollständig abgeschlossen werden kann, bedeutet dies nicht, dass der gesamte Status des Programms Müll ist. Nur weil der Parkplatz voller Autos ist, heißt das nicht, dass Sie Ihr Auto wegwerfen. Entweder warten Sie eine Weile, bis ein Stand frei ist, oder Sie fahren in ein weiter entferntes Geschäft, um Ihre Kekse zu kaufen.

In den meisten Fällen gibt es einen alternativen Weg. Wenn Sie einen Fehler nicht behebbar machen, werden viele Optionen effektiv entfernt, und keiner von uns möchte, dass jemand für uns entscheidet, was wir können und was nicht.

Gleiches gilt für den Speicherplatz. Es ist wirklich die gleiche Argumentation. Und im Gegensatz zu Ihrer Andeutung, dass ein Stapelüberlauf nicht behebbar ist, würde ich sagen, dass dies eine willkürliche Einschränkung ist. Es gibt keinen guten Grund, warum Sie nicht in der Lage sein sollten, eine Ausnahme auszulösen (viele Frames zu knallen) und dann einen anderen, weniger effizienten Ansatz zu verwenden, um die Arbeit zu erledigen.

Meine zwei Cent :-)


0

Wenn Sie wirklich kein Gedächtnis mehr haben, sind Sie zum Scheitern verurteilt, da Sie nichts mehr befreien können.

Wenn Sie nicht mehr genügend Speicher haben, aber so etwas wie ein Garbage Collector einspringen und Speicher freigeben kann, sind Sie noch nicht tot.

Das andere Problem ist die Fragmentierung. Obwohl Sie möglicherweise nicht über genügend Speicher verfügen (fragmentiert), können Sie möglicherweise nicht den großen Teil zuweisen, den Sie haben möchten.


0

Ich weiß, dass Sie nach Argumenten gefragt haben, aber ich kann nur Argumente dagegen sehen.

Ich sehe sowieso nicht, um dies in einer Multithread-Anwendung zu erreichen. Woher wissen Sie, welcher Thread tatsächlich für den Fehler aufgrund von Speichermangel verantwortlich ist? Ein Thread könnte ständig neuen Speicher zuweisen und 99% des Heaps mit GC-Roots versehen, aber die erste fehlgeschlagene Zuordnung erfolgt in einem anderen Thread.

Ein praktisches Beispiel: Wenn in unserer Java-Anwendung ein OutOfMemoryError aufgetreten ist (der auf einem JBoss-Server ausgeführt wird), stirbt nicht ein Thread, und der Rest des Servers wird weiterhin ausgeführt: Nein, es gibt mehrere OOMEs, die mehrere Threads (einige) beenden davon sind die internen Threads von JBoss). Ich sehe nicht ein, was ich als Programmierer tun könnte, um mich davon zu erholen - oder was JBoss tun könnte, um sich davon zu erholen. Tatsächlich bin ich mir nicht einmal sicher, ob Sie KÖNNEN : Das Javadoc für VirtualMachineError schlägt vor, dass die JVM möglicherweise "defekt" ist, nachdem ein solcher Fehler ausgelöst wurde. Aber vielleicht war die Frage eher auf das Sprachdesign ausgerichtet.


0

uClibc verfügt über einen internen statischen Puffer von ca. 8 Byte für Datei-E / A, wenn kein Speicher mehr dynamisch zugewiesen werden muss.


0

Was ist das überzeugende Argument dafür, dass es sich um einen behebbaren Fehler handelt?

In Java ist ein zwingendes Argument dafür , dass es sich nicht um einen behebbaren Fehler handelt, dass Java die Signalisierung von OOM jederzeit ermöglicht, auch zu Zeiten, in denen Ihr Programm möglicherweise in einen inkonsistenten Zustand wechselt. Eine zuverlässige Rückgewinnung aus einem OOM ist daher nicht möglich. Wenn Sie die OOM-Ausnahme abfangen, können Sie sich auf keinen Ihrer Programmstatus verlassen. Siehe VirtualMachineError-Garantien ohne Auswurf


0

Ich arbeite an SpiderMonkey, der in Firefox verwendeten JavaScript-VM (und Gnome und einigen anderen). Wenn Sie nicht mehr genügend Speicher haben, möchten Sie möglicherweise eines der folgenden Dinge tun:

  1. Führen Sie den Garbage-Collector aus. Wir führen den Garbage-Collector nicht die ganze Zeit aus, da dies die Leistung und den Akku beeinträchtigen würde. Wenn Sie also einen Speicherfehler haben, hat sich möglicherweise etwas Müll angesammelt.
  2. Freier Speicher. Entfernen Sie beispielsweise einen Teil des In-Memory-Cache.
  3. Töte oder verschiebe nicht wesentliche Aufgaben. Entladen Sie beispielsweise einige Registerkarten, die seit langem nicht mehr verwendet werden, aus dem Speicher.
  4. Protokollieren Sie Dinge, um dem Entwickler bei der Behebung des Speichermangels zu helfen.
  5. Zeigen Sie eine halbwegs nette Fehlermeldung an, um den Benutzer über die aktuellen Ereignisse zu informieren.
  6. ...

Ja, es gibt viele Gründe, nicht genügend Speicherfehler manuell zu behandeln!


-1

Ich habe das:

void *smalloc(size_t size) {
  void *mem = null; 
  for(;;) {
   mem = malloc(size);
   if(mem == NULL) {
    sleep(1);
   } else 
     break;
  }
  return mem;
}

Was schon einige Male ein System gerettet hat. Nur weil Ihnen jetzt der Arbeitsspeicher ausgeht, bedeutet dies nicht, dass ein anderer Teil des Systems oder andere Prozesse, die auf dem System ausgeführt werden, über Speicher verfügen, den sie bald zurückgeben werden. Seien Sie besser sehr, sehr vorsichtig, bevor Sie solche Tricks versuchen, und haben Sie die Kontrolle über jeden Speicher, den Sie in Ihrem Programm zuweisen.


Was ist, wenn ein anderer Prozess den gesamten Speicher belegt und ihn nicht an das Betriebssystem zurückgibt? dann wirst du für immer auf dem Laufenden bleiben, egal was los ist. Wäre es nicht besser, wenn etwas protokolliert werden könnte?
Matt

1
Sicher. Das obige ist nur ein Beispiel, Sie könnten etwas protokollieren, Sie könnten es nur 20 Mal anstelle einer Endlosschleife versuchen usw.
Nr.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.