Was ist der Zweck von Speicherüberlastung unter Linux?


8

Ich kenne mich mit Überbeanspruchung des Gedächtnisses aus und mag es zutiefst nicht und deaktiviere es normalerweise.

Ein gut geschriebenes Programm kann malloc(oder mmapwird häufig verwendet malloc) mehr Speicher als verfügbar und stürzt ab, wenn es verwendet wird. Ohne Speicherüberlastung würde dies mallocoder mmapfehlschlagen, und das gut geschriebene Programm würde diesen Fehler abfangen. Das schlecht geschriebene Programm ( mallocohne Prüfung auf Fehler) stürzt ab, wenn das Ergebnis eines Fehlers verwendet wird malloc.

Natürlich ist der virtuelle Adressraum (der um mmapso erweitert wird malloc) nicht dasselbe wie RAM (RAM ist eine vom Kernel verwaltete Ressource, siehe dies ; Prozesse haben ihren virtuellen Adressraum durch execve (2) initialisiert und durch mmap& sbrkso don erweitert verbrauchen nicht direkt RAM, nur virtuellen Speicher ).

Beachten Sie, dass die Optimierung der RAM-Nutzung mit madvise (2) erfolgen kann (was einen Hinweis geben kann, indem MADV_DONTNEEDder Kernel verwendet wird, um einige Seiten auf die Festplatte zu tauschen), wenn dies wirklich erforderlich ist. Programme, die eine Überbindung wünschen, könnten mmap (2) mit verwenden MAP_NORESERVE. Mein Verständnis von Speicherüberbelegung ist, als ob jede Speicherzuordnung (von execveoder mmap) implizit verwendet wirdMAP_NORESERVE

Meiner Meinung nach ist es einfach nützlich für sehr fehlerhafte Programme. Aber meiner Meinung nach ein echter Entwickler sollte immer überprüfen Ausfall malloc, mmapund den dazugehörigen virtuellen Adressraum wechselnden Funktionen (zB wie hier ). Und die meisten freien Softwareprogramme, deren Quellcode ich studiert habe, haben eine solche Prüfung, vielleicht als eine xmallocFunktion ....

Gibt es echte Programme, z. B. in typischen Linux-Distributionen, die tatsächlich Speicherüberlastung benötigen und auf vernünftige und nützliche Weise nutzen? Ich kenne keinen von ihnen!

Was sind die Nachteile des Deaktivierens von Speicherüberlastung? Viele ältere Unixe (z. B. SunOS4, SunOS5 aus dem vorigen Jahrhundert) hatten es nicht, und meiner Meinung nach war ihre malloc(und vielleicht sogar die allgemeine Leistung des mallocgesamten Systems ) nicht viel schlechter (und Verbesserungen seitdem hängen nicht mit einer Überlastung des Speichers zusammen). .

Ich glaube, dass eine Überbelegung des Speichers eine Fehlfunktion für faule Programmierer ist.


2
Bestimmte Pakete Rhaben Probleme mit OpenBSD, weil sie viel virtuellen Speicher benötigen und OpenBSD sagt nein. Dieselben Pakete sind unter Linux in Ordnung und führen nicht dazu, dass der verrückte betrunkene Oom-Killer am Prozesstisch wegsprengt.
Thrig

1
@ Thrig das könnte eine Antwort sein, vor allem wenn Sie spezifischer waren. Welche R-Pakete? Können sie noch in der Praxis arbeiten? Warum brauchen sie Speicherüberlastung?
Basile Starynkevitch

das war vor 5 Jahren , und ich konnte das problematische Paket (oder so wurde behoben, mittlerweile ...) in einer kurzen Suche nicht gefunden
thrig

Ein paar Kommentare zu den Änderungen, die Sie an der Frage vorgenommen haben: Ohne Speicherüberlastung würde ein Aufruf von malloc fehlschlagen, selbst wenn noch genügend Speicher verfügbar ist. Ich halte es für unrealistisch, alle Programme zur Verwendung zu verpflichten madvise. Der Kernel erhält den Hinweis normalerweise ohnehin automatisch, indem er zählt, welche Seiten kürzlich verwendet wurden und welche nicht. Das MAP_NORESERVEFlag für den mmapSystemaufruf bedeutet nur, dass kein Swap-Speicherplatz für die Zuordnung reserviert ist und das Anforderungs-Paging nicht deaktiviert wird.
Johan Myréen

Auf welche Art von "viel Gedächtnis" beziehen Sie sich? virtueller Speicher oder RAM? IMHO RAM wird vom Kernel verwaltet, und der Anwendungscode kümmert sich nicht darum. Es verwendet den virtuellen Adressraum.
Basile Starynkevitch

Antworten:


12

Der Grund für die Überbindung besteht darin, eine Unterauslastung des physischen Arbeitsspeichers zu vermeiden. Es gibt einen Unterschied zwischen der Menge an virtuellem Speicher, die ein Prozess zugewiesen hat, und der Menge an virtuellem Speicher, die tatsächlich physischen Seitenrahmen zugeordnet wurde. Tatsächlich reserviert ein Prozess direkt nach dem Start sehr wenig RAM. Dies ist auf das Anforderungs-Paging zurückzuführen: Der Prozess verfügt über ein virtuelles Speicherlayout, die Zuordnung von der Adresse des virtuellen Speichers zu einem physischen Seitenrahmen wird jedoch erst hergestellt, wenn der Speicher gelesen oder geschrieben wurde.

Ein Programm verwendet normalerweise nie den gesamten virtuellen Speicherplatz, und die berührten Speicherbereiche variieren während der Programmausführung. Beispielsweise können Zuordnungen zu Seitenrahmen, die Initialisierungscode enthalten und nur zu Beginn des Laufs ausgeführt werden, verworfen und die Seitenrahmen für andere Zuordnungen verwendet werden.

Gleiches gilt für Daten: Wenn ein Programm aufruft malloc, reserviert es einen ausreichend großen zusammenhängenden virtuellen Adressraum zum Speichern von Daten. Zuordnungen zu physischen Seitenrahmen werden jedoch erst erstellt, wenn die Seiten tatsächlich verwendet werden, wenn überhaupt . Oder betrachten Sie den Programmstapel: Jeder Prozess erhält einen ziemlich großen zusammenhängenden virtuellen Speicherbereich, der für den Stapel reserviert ist (normalerweise 8 MB). Ein Prozess verwendet normalerweise nur einen Bruchteil dieses Stapelspeichers. kleine und gut erzogene Programme verbrauchen noch weniger.

Ein Linux-Computer verfügt normalerweise über viele heterogene Prozesse, die in verschiedenen Phasen ihrer Lebensdauer ausgeführt werden. Statistisch gesehen benötigen sie zu keinem Zeitpunkt gemeinsam eine Zuordnung für jede virtuelle Seite, die ihnen zugewiesen wurde (oder später im Programmlauf zugewiesen wird).

Ein streng unverbindliches Schema würde eine statische Zuordnung von virtuellen Adressseiten zu physischen RAM-Seitenrahmen zum Zeitpunkt der Zuweisung der virtuellen Seiten erstellen. Dies würde zu einem System führen, das weit weniger Programme gleichzeitig ausführen kann, da viele RAM-Seitenrahmen für nichts reserviert wären.

Ich leugne nicht, dass das Überbeanspruchen von Speicher seine Gefahren birgt und zu Situationen führen kann, in denen es zu wenig Speicher gibt. Es geht darum, den richtigen Kompromiss zu finden.


Das Vermeiden einer Unterauslastung des Arbeitsspeichers kann mit madvise (2) unter Verwendung von MADV_DONTNEED(und sollte möglicherweise von Anwendungen erfolgen) erfolgen, daher bin ich immer noch nicht sehr überzeugt. Aber deine Erklärung ist interessant, also danke!
Basile Starynkevitch

Und das übliche Schema wäre, virtuellen Speicher zu reservieren (indem er auf dem Auslagerungsbereich
zugewiesen wird

2
Prozesse haben einen virtuellen Adressraum (im virtuellen Speicher). RAM wird systemweit vom Kernel verwaltet.
Seien Sie

4

Sie sagen dies, als ob Faulheit beim Programmieren nicht als Tugend angesehen wird :).

Große Mengen an Software sind auf Einfachheit und Wartbarkeit optimiert, wobei das Überleben von Bedingungen mit geringem Arbeitsspeicher eine sehr niedrige Priorität hat. Es ist üblich, Zuordnungsfehler als tödlich zu behandeln. Durch das Beenden des Prozesses, der den Speicher erschöpft, wird eine Situation vermieden, in der kein freier Speicher vorhanden ist und das System keine Fortschritte erzielen kann, ohne entweder mehr Speicher oder Komplexität in Form einer umfassenden Vorzuweisung zuzuweisen.

Beachten Sie, wie fein der Unterschied zwischen dem Überprüfen von Zuordnungen und dem Sterben oder dem Nicht-Überprüfen und Abstürzen ist. Es wäre nicht fair, Programmierern die Schuld an Overcommit zu geben, ohne sich darum zu kümmern, ob malloc () erfolgreich war oder fehlgeschlagen ist.

Es gibt nur eine kleine Menge an Software, der Sie vertrauen können, dass sie trotz fehlgeschlagener Zuweisungen "korrekt" fortfährt. Es sollte allgemein erwartet werden, dass der Kernel überlebt. sqlite verfügt über einen notorisch robusten Test, der auch Tests außerhalb des Speichers umfasst, insbesondere weil verschiedene kleine eingebettete Systeme unterstützt werden sollen.

Als Fehlerpfad, der im normalen Betrieb nicht verwendet wird, bedeutet die korrekte Behandlung von Bedingungen mit geringem Arbeitsspeicher eine erhebliche zusätzliche Belastung für Wartung und Test. Wenn dieser Aufwand keinen angemessenen Nutzen bringt, kann er an anderer Stelle rentabler eingesetzt werden .

Wenn dies zusammenbricht, ist es auch üblich, Sonderfälle für große Zuweisungen zu haben, um die häufigsten Fehlerursachen zu behandeln.

In diesem Zusammenhang ist es wahrscheinlich am besten, ein bestimmtes Maß an Überbindung zuzulassen . Es ist Teil des aktuellen Standardkompromisses unter Linux.

Beachten Sie, dass die Idee, dass man Overcommit auf Kernel-Ebene deaktivieren und stattdessen mehr Swap bereitstellen sollte, als Sie jemals verwenden möchten, auch seine Hasser hat. Die Geschwindigkeitslücke zwischen RAM und rotierenden Festplatten hat sich im Laufe der Zeit vergrößert, sodass das System, wenn es tatsächlich den von Ihnen zugelassenen Swap-Speicherplatz nutzt, häufiger als "Stillstand" bezeichnet werden kann.


Faulheit könnte es rechtfertigen, den freegrößten mallocSpeicherplatz nicht zu belasten und den Betriebssystemkernel zu verlassen, um den Prozess nach seiner Beendigung ordnungsgemäß zu bereinigen
Basile Starynkevitch

4

Ich stimme der Antwort von Johan Myréen zu und habe sie positiv bewertet, aber hier sind weitere Erklärungen, die Ihnen helfen könnten, das Problem zu verstehen.

Sie scheinen den Auslagerungsbereich zu verwirren, dh auf dem Speicherplatz, auf dem weniger genutzter RAM und virtueller Speicher gespeichert werden sollen. Letzteres besteht aus einer Kombination von RAM-Bereichen und Festplattenbereichen.

Prozesse reservieren und verwenden virtuellen Speicher. Sie haben keine Ahnung, wo es gespeichert ist. Wenn sie auf Daten zugreifen müssen, die sich nicht im RAM befinden, werden Prozesse (oder Threads) angehalten, bis der Kernel die Aufgabe erledigt, dass die Datenseite verfügbar ist.

Wenn RAM benötigt wird, gibt der Kernel etwas RAM frei, indem weniger verwendete Prozessseiten im Plattenaustauschbereich gespeichert werden.

Wenn ein Prozess Speicher reserviert (z. B. Malloc und dergleichen), markieren nicht überlastete Betriebssysteme nicht verwendete Teile des virtuellen Speichers als nicht verfügbar. Das heißt, wenn der Prozess, der die Zuordnung vorgenommen hat, tatsächlich auf die reservierten Seiten zugreifen muss, wird garantiert, dass sie vorhanden sind.

Der Nachteil besteht darin, dass der Speicher von keinem anderen Prozess verwendet werden kann und verhindert, dass diese Seiten ihre Seiten paginieren, sodass RAM verschwendet wird, wenn diese Prozesse inaktiv sind. Am schlimmsten ist, wenn die Summe der Reservierungen größer als die Größe des Auslagerungsbereichs ist, werden auch RAM-Seiten reserviert, um der Reservierung zu entsprechen, obwohl sie keine Daten enthalten. Dies ist ein ziemlich schlechtes Szenario, da Sie über RAM verfügen, das sowohl unbrauchbar als auch unbenutzt ist. Schließlich besteht das schlimmste Szenario darin, dass eine große Reservierung nicht akzeptiert werden kann, da kein virtueller Speicher (Swap + RAM) mehr verfügbar ist. Der Vorgang der Reservierung stürzt normalerweise ab.

Wenn Sie jedoch Betriebssysteme wie Linux überbeanspruchen, wird es zu keinem Zeitpunkt zu einem Mangel an virtuellem Speicher kommen. Sie akzeptieren die meisten Speicherreservierungen (aber keine unrealistischen, dies kann mehr oder weniger optimiert werden) und ermöglichen im Allgemeinen eine bessere Nutzung des RAM und der Swap-Ressourcen.

Dies ähnelt der Überbuchung von Sitzplätzen durch Fluggesellschaften. Dies verbessert die Auslastung, aber einige Passagiere könnten unglücklich sein. Hoffentlich buchen Fluggesellschaften sie einfach für einen anderen Flug und entschädigen sie möglicherweise, während Linux nur die schwereren Passagiere aus dem Flugzeug wirft ...

Zusammenfassend lässt sich sagen, dass Linux den Speicher faul und nach besten Kräften reserviert, während mehrere andere Betriebssysteme Reservierungen garantieren.

In realen Fällen, in denen eine Überbindung sehr sinnvoll ist, führt ein Programm, das viel virtuellen Speicher verwendet, eine Abzweigung durch, gefolgt von einer Ausführung.

Angenommen, Sie haben 4 GB RAM, von denen 3 GB für den virtuellen Speicher und 4 GB Swap verfügbar sind. Es gibt einen Prozess, der 4 GB reserviert, aber nur 1 GB davon verwendet. Es gibt keine Paginierung, daher funktioniert das System gut. Auf einem nicht überlasteten Betriebssystem kann dieser Prozess nicht verzweigt werden, da unmittelbar nach dem Verzweigen 4 GB mehr virtueller Speicher reserviert werden müssen und nur noch 3 GB übrig sind.

Unter Linux wird dieser Fork- (oder Klon-) Systemaufruf erfolgreich abgeschlossen (aber unter dem Deckmantel betrogen), und nach der folgenden Ausführung (falls vorhanden) werden diese reservierten, aber nicht verwendeten 4 GB ohne Schaden freigegeben.


1

Spärliche Arrays

man procfür /proc/sys/vm/overcommit_memoryzitiert tatsächlich eine Anwendung:

In Modus 1 gibt der Kernel vor, immer genügend Speicher vorhanden zu sein, bis der Speicher tatsächlich aufgebraucht ist. Ein Anwendungsfall für diesen Modus sind wissenschaftliche Computeranwendungen, die große, spärliche Arrays verwenden.

Ich bin mir nicht sicher, ob dies tatsächlich in der Praxis verwendet wird.

Weitere Informationen /proc/sys/vm/overcommit_memoryunter: /programming/2798330/maximum-memory-which-malloc-can-allocate/57687432#57687432

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.