Kann Linux "kein RAM mehr" haben?

20

Ich habe mehrere Posts im Internet gesehen, in denen sich Leute anscheinend über einen gehosteten VPS beschwert haben, der Prozesse unerwartet beendet hat, weil sie zu viel RAM verwendet haben.

Wie ist das möglich? Ich dachte, alle modernen Betriebssysteme bieten "unendlichen RAM", indem sie nur den Festplattentausch für alles verwenden, was über den physischen RAM geht. Ist das richtig?

Was kann passieren, wenn ein Prozess "wegen zu wenig RAM abgebrochen" wird?

der Spiegel
quelle
12
Kein Betriebssystem hat unendlich RAM. Zusätzlich zu den physischen RAM-Chips in der Maschine können Betriebssysteme - normalerweise optional - eine sogenannte Auslagerungsdatei verwenden, die sich auf der Festplatte befindet. Wenn ein Computer mehr Speicher benötigt als RAM-Sticks, werden einige Daten in die Auslagerungsdatei ausgelagert. Sobald die Auslagerungsdatei ihre Kapazität erreicht hat - entweder weil Sie eine maximale Größe festgelegt haben (typisch) oder weil die Festplatte voll ist -, ist der virtuelle Speicher voll.
John Dibling
@JohnDibling; Gibt es einen Grund, warum man die Auslagerungsgröße begrenzen möchte, außer um Speicherplatz für das Dateisystem zu sparen? Mit anderen Worten, wenn ich eine 20-GB-Festplatte und nur 1 GB Dateien habe, gibt es einen Grund, meine Auslagerungsgröße nicht auf 19 GB festzulegen?
Themirror
1
Um die Dinge zu vereinfachen, würde ich sagen, dass die beiden Gründe für die Begrenzung der Swap-Größe 1) die Reduzierung des Festplattenverbrauchs und 2) die Steigerung der Leistung sind. Letzteres könnte mehr wahr unter Windows als / * NICHTS, aber dann wieder, wenn Sie mit dem Swap - Speicher auf der Festplatte, Ihre Leistung verschlechtert. Der Datenträgerzugriff ist je nach System entweder langsamer als der Arbeitsspeicher oder wesentlich langsamer als der Arbeitsspeicher.
John Dibling
9
Swap ist kein RAM . en.wikipedia.org/wiki/Random-access_memory Die Größe des Arbeitsspeichers in Ihrem System ist die Größe des Arbeitsspeichers in Ihrem System - Zeitraum. Es ist kein mehrdeutiges oder dynamisches Volumen. Es ist absolut festgelegt. "Speicher" ist ein mehrdeutiger Begriff, aber die Unterscheidung zwischen RAM und anderen Speicherformen ist, wie Terdon (+1) hervorhebt, ziemlich bedeutsam. Der Festplattentausch kann die Leistung des Arbeitsspeichers nicht um viele Größenordnungen ersetzen . Ein System, das zu stark vom Tausch abhängig ist, ist bestenfalls vorübergehend und im Allgemeinen: Müll.
Goldlöckchen
1
Also ist der Speicherplatz jetzt unendlich?
Kaz

Antworten:

41

Was kann passieren, wenn ein Prozess "wegen zu wenig RAM abgebrochen" wird?

Es wird manchmal gesagt, dass Linux standardmäßig niemals Anfragen nach mehr Speicher aus dem Anwendungscode ablehnt - z malloc(). 1 Dies ist in der Tat nicht wahr; Standardmäßig wird eine Heuristik verwendet

Offensichtliche Überlastungen des Adressraums werden abgelehnt. Wird für ein typisches System verwendet. Es stellt sicher, dass eine ernsthafte Wild-Allocation fehlschlägt, und ermöglicht gleichzeitig eine Überbeanspruchung, um die Swap-Nutzung zu reduzieren.

Von [linux_src]/Documentation/vm/overcommit-accounting(alle Anführungszeichen stammen aus dem 3.11-Baum). Was genau als "ernsthafte wilde Zuordnung" gilt, wird nicht explizit angegeben, daher müssten wir die Quelle durchgehen, um die Details zu bestimmen. Wir könnten auch die experimentelle Methode in Fußnote 2 (unten) verwenden, um zu versuchen, eine Reflexion der Heuristik zu erhalten. Meine erste empirische Beobachtung ist, dass unter idealen Umständen (== das System ist im Leerlauf), wenn Sie nicht " Wenn Sie keinen Swap haben, können Sie ungefähr die Hälfte Ihres Arbeitsspeichers zuweisen. Wenn Sie Swap haben, erhalten Sie ungefähr die Hälfte Ihres Arbeitsspeichers plus den gesamten Swap. Das ist mehr oder weniger pro Prozess (Beachten Sie jedoch , diese Grenze ist dynamisch und Änderungen vorbehalten wegen der staatlichen finden einige Beobachtungen in Fußnote 5).

Die Hälfte Ihres Arbeitsspeichers plus Swap ist explizit die Standardeinstellung für das Feld "CommitLimit" in /proc/meminfo. Das bedeutet Folgendes - und beachten Sie, dass dies eigentlich nichts mit dem soeben diskutierten Grenzwert (von [src]/Documentation/filesystems/proc.txt) zu tun hat :

CommitLimit: Basierend auf dem Overcommit-Verhältnis ('vm.overcommit_ratio') ist dies die Gesamtmenge des Arbeitsspeichers, die derzeit auf dem System verfügbar ist. Dieses Limit wird nur eingehalten, wenn die strikte Überlastungsabrechnung aktiviert ist (Modus 2 in 'vm.overcommit_memory'). Das CommitLimit wird mit der folgenden Formel berechnet: CommitLimit = ('vm.overcommit_ratio' * Physical RAM) + Swap Zum Beispiel würde es auf einem System mit 1G physischem RAM und 7G Swap mit einem 'vm.overcommit_ratio' von 30 ergeben ein CommitLimit von 7.3G.

Das zuvor zitierte Dokument zur Überlastungsabrechnung gibt an, dass der Standardwert vm.overcommit_ratio50 ist. Wenn Sie dies also sysctl vm.overcommit_memory=2tun, können Sie vm.covercommit_ratio (mit sysctl) anpassen und die Konsequenzen anzeigen . 3 Der Standardmodus ist, wenn er CommitLimitnicht erzwungen wird und nur "offensichtliche Überschreibungen des Adressraums abgelehnt werden", wenn vm.overcommit_memory=0.

Während die Standardstrategie ein heuristisches Pro-Prozess-Limit hat, das die "ernsthafte wilde Allokation" verhindert, kann das System als Ganzes ernsthaft wild und allokationsweise werden. 4 Dies bedeutet, dass irgendwann nicht mehr genügend Arbeitsspeicher zur Verfügung steht und über den OOM-Killer Konkurs für einen oder mehrere Prozesse angemeldet werden muss .

Was tötet der OOM-Killer? Nicht unbedingt der Prozess, der nach Speicher gefragt hat, als es keinen gab, da dies nicht unbedingt der wirklich schuldige Prozess ist, und was noch wichtiger ist, nicht unbedingt der Prozess, der das System am schnellsten von dem Problem befreit, in dem es sich befindet.

Dies wird hier zitiert , wo wahrscheinlich eine 2.6.x-Quelle zitiert wird:

/*
 * oom_badness - calculate a numeric value for how bad this task has been
 *
 * The formula used is relatively simple and documented inline in the
 * function. The main rationale is that we want to select a good task
 * to kill when we run out of memory.
 *
 * Good in this context means that:
 * 1) we lose the minimum amount of work done
 * 2) we recover a large amount of memory
 * 3) we don't kill anything innocent of eating tons of memory
 * 4) we want to kill the minimum amount of processes (one)
 * 5) we try to kill the process the user expects us to kill, this
 *    algorithm has been meticulously tuned to meet the principle
 *    of least surprise ... (be careful when you change it)
 */

Das scheint eine anständige Begründung zu sein. Ohne forensisch zu werden, scheint jedoch # 5 (die redundant zu # 1 ist) eine schwierige Verkaufsimplementierung zu sein, und # 3 ist redundant zu # 2. Es könnte also sinnvoll sein, dies auf # 2/3 und # 4 zu reduzieren.

Ich habe mich in einer kürzlich erschienenen Quelle (3.11) umgesehen und festgestellt, dass sich dieser Kommentar in der Zwischenzeit geändert hat:

/**
 * oom_badness - heuristic function to determine which candidate task to kill
 *
 * The heuristic for determining which task to kill is made to be as simple and
 * predictable as possible.  The goal is to return the highest value for the
 * task consuming the most memory to avoid subsequent oom failures.
 */

Dies ist ein wenig mehr explizit über # 2: „Das Ziel ist es , [töten] die Aufgabe , die meisten Speicherraubend nachfolgende oom Ausfälle zu vermeiden“ , und durch Implikation # 4 ( „wir wollen die minimale Menge an Prozesse töten ( eine ) ) .

Wenn Sie den OOM-Killer in Aktion sehen möchten, lesen Sie Fußnote 5.


1 Eine Täuschung, die Gilles mich dankbar loswurde, siehe Kommentare.


2 Hier ist ein einfaches Bit von C, das nach immer größeren Speicherblöcken fragt, um festzustellen, wann eine Anforderung nach mehr fehlschlägt:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#define MB 1 << 20

int main (void) {
    uint64_t bytes = MB;
    void *p = malloc(bytes);
    while (p) {
        fprintf (stderr,
            "%lu kB allocated.\n",
            bytes / 1024
        );
        free(p);
        bytes += MB;
        p = malloc(bytes);
    }
    fprintf (stderr,
        "Failed at %lu kB.\n",
        bytes / 1024
    );
    return 0;
}            

Wenn Sie C nicht kennen, können Sie es kompilieren gcc virtlimitcheck.c -o virtlimitcheckund dann ausführen ./virtlimitcheck. Es ist völlig harmlos, da der Prozess keinen der benötigten Speicherplätze belegt - dh, er verwendet nie wirklich RAM.

Auf einem 3,11 x 86_64-System mit 4 GB System und 6 GB Swap schlug ich bei ~ 7400000 kB fehl. Die Anzahl schwankt, also ist der Zustand vielleicht ein Faktor. Dies ist zufällig nahe der CommitLimitin /proc/meminfo, aber diese durch Modifikation vm.overcommit_ratiokeinen Unterschied machen. Auf einem 3.6.11 32-Bit ARM 448 MB System mit 64 MB Swap scheitere ich jedoch bei ~ 230 MB. Dies ist interessant, da im ersten Fall die Menge fast doppelt so groß ist wie der RAM-Speicher, während im zweiten Fall etwa 1/4 der Swap-Größe eine Rolle spielt. Dies wurde durch Ausschalten von Swap auf dem ersten System bestätigt, als die Ausfallschwelle auf ~ 1,95 GB sank, ein sehr ähnliches Verhältnis wie bei der kleinen ARM-Box.

Aber ist das wirklich pro Prozess? Es scheint zu sein. Das kurze Programm unten fragt nach einem benutzerdefinierten Speicherblock und wartet bei Erfolg darauf, dass Sie die Eingabetaste drücken. Auf diese Weise können Sie mehrere Instanzen gleichzeitig ausführen:

#include <stdio.h>
#include <stdlib.h>

#define MB 1 << 20

int main (int argc, const char *argv[]) {
    unsigned long int megabytes = strtoul(argv[1], NULL, 10);
    void *p = malloc(megabytes * MB);
    fprintf(stderr,"Allocating %lu MB...", megabytes);
    if (!p) fprintf(stderr,"fail.");
    else {
        fprintf(stderr,"success.");
        getchar();
        free(p);
    }
    return 0;
}

Beachten Sie jedoch, dass es unabhängig von der Verwendung nicht ausschließlich um die Größe des Arbeitsspeichers und des Auslagerungsspeichers geht. In Fußnote 5 finden Sie Hinweise zu den Auswirkungen des Systemzustands.


3 CommitLimit bezieht sich auf die Menge an Adressraum, die für das System zulässig ist , wenn vm.overcommit_memory = 2. Vermutlich sollte die Menge, die Sie zuweisen können, minus der bereits festgeschriebenen Menge sein, was anscheinend das Committed_ASFeld ist.

Ein potenziell interessantes Experiment, das dies demonstriert, ist das Hinzufügen #include <unistd.h>von oben in virtlimitcheck.c (siehe Fußnote 2) und fork()rechts vor der while()Schleife. Es ist nicht garantiert, dass dies ohne langwierige Synchronisierung wie hier beschrieben funktioniert, aber es besteht eine gute Chance, dass dies der Fall ist, YMMV:

> sysctl vm.overcommit_memory=2
vm.overcommit_memory = 2
> cat /proc/meminfo | grep Commit
CommitLimit:     9231660 kB
Committed_AS:    3141440 kB
> ./virtlimitcheck 2&> tmp.txt
> cat tmp.txt | grep Failed
Failed at 3051520 kB.
Failed at 6099968 kB.

Dies ist sinnvoll. Wenn Sie sich die Datei tmp.txt im Detail ansehen, können Sie sehen, dass die Prozesse ihre immer größeren Zuordnungen abwechseln (dies ist einfacher, wenn Sie die PID in die Ausgabe werfen), bis einer offensichtlich genug behauptet hat, dass der andere fehlschlägt. Dem Gewinner steht es dann frei, alles bis zum CommitLimitMinus zu greifen Committed_AS.


4 An dieser Stelle ist zu erwähnen, dass, wenn Sie die virtuelle Adressierung und das Anfordern von Paging noch nicht verstehen, die Möglichkeit einer Überbindung in erster Linie darin besteht, dass der Kernel Userland-Prozessen überhaupt keinen physischen Speicher zuweist, sondern diesen virtueller Adressraum . Wenn ein Prozess beispielsweise 10 MB für etwas reserviert, ist dies eine Folge von (virtuellen) Adressen, aber diese Adressen entsprechen noch nicht dem physischen Speicher. Wenn auf eine solche Adresse zugegriffen wird, führt dies zu einem Seitenfehlerund dann versucht der Kernel, es auf den realen Speicher abzubilden, so dass es einen realen Wert speichern kann. Prozesse reservieren in der Regel viel mehr virtuellen Speicherplatz als sie tatsächlich in Anspruch nehmen, wodurch der Kernel den Arbeitsspeicher am effizientesten nutzen kann. Der physische Speicher ist jedoch immer noch eine begrenzte Ressource, und wenn er vollständig dem virtuellen Adressraum zugeordnet wurde, muss ein Teil des virtuellen Adressraums entfernt werden, um RAM freizugeben.


5 Zuerst eine Warnung : Wenn Sie dies mit versuchen vm.overcommit_memory=0, stellen Sie sicher, dass Sie Ihre Arbeit zuerst speichern und alle kritischen Anwendungen schließen, da das System für ~ 90 Sekunden eingefroren wird und ein Prozess abstürzt!

Die Idee ist, eine Gabelbombe zu starten , deren Zeit nach 90 Sekunden abläuft, wobei die Gabeln Speicherplatz zuweisen und einige von ihnen große Datenmengen in den RAM schreiben, während sie an stderr berichten.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>

/* 90 second "Verbose hungry fork bomb".
Verbose -> It jabbers.
Hungry -> It grabs address space, and it tries to eat memory.

BEWARE: ON A SYSTEM WITH 'vm.overcommit_memory=0', THIS WILL FREEZE EVERYTHING
FOR THE DURATION AND CAUSE THE OOM KILLER TO BE INVOKED.  CLOSE THINGS YOU CARE
ABOUT BEFORE RUNNING THIS. */

#define STEP 1 << 30 // 1 GB
#define DURATION 90

time_t now () {
    struct timeval t;
    if (gettimeofday(&t, NULL) == -1) {
        fprintf(stderr,"gettimeofday() fail: %s\n", strerror(errno));
        return 0;
    }
    return t.tv_sec;
}

int main (void) {
    int forks = 0;
    int i;
    unsigned char *p;
    pid_t pid, self;
    time_t check;
    const time_t start = now();
    if (!start) return 1;

    while (1) {
    // Get our pid and check the elapsed time.
        self = getpid();
        check = now();
        if (!check || check - start > DURATION) return 0;
        fprintf(stderr,"%d says %d forks\n", self, forks++);
    // Fork; the child should get its correct pid.
        pid = fork();
        if (!pid) self = getpid();
    // Allocate a big chunk of space.
        p = malloc(STEP);
        if (!p) {
            fprintf(stderr, "%d Allocation failed!\n", self);
            return 0;
        }
        fprintf(stderr,"%d Allocation succeeded.\n", self);
    // The child will attempt to use the allocated space.  Using only
    // the child allows the fork bomb to proceed properly.
        if (!pid) {
            for (i = 0; i < STEP; i++) p[i] = i % 256;
            fprintf(stderr,"%d WROTE 1 GB\n", self);
        }
    }
}                        

Kompilieren Sie dies gcc forkbomb.c -o forkbomb. Versuchen Sie es zuerst mit sysctl vm.overcommit_memory=2- Sie werden wahrscheinlich etwas bekommen wie:

6520 says 0 forks
6520 Allocation succeeded.
6520 says 1 forks
6520 Allocation succeeded.
6520 says 2 forks
6521 Allocation succeeded.
6520 Allocation succeeded.
6520 says 3 forks
6520 Allocation failed!
6522 Allocation succeeded.

In dieser Umgebung kommt diese Art von Gabelbombe nicht sehr weit. Beachten Sie, dass die Anzahl in "sagt N Gabeln" nicht die Gesamtzahl der Prozesse ist, sondern die Anzahl der Prozesse in der Kette / dem Zweig, die zu diesem Prozess führen.

Probieren Sie es jetzt mit vm.overcommit_memory=0. Wenn Sie stderr in eine Datei umleiten, können Sie anschließend eine grobe Analyse durchführen, z.

> cat tmp.txt | grep failed
4641 Allocation failed!
4646 Allocation failed!
4642 Allocation failed!
4647 Allocation failed!
4649 Allocation failed!
4644 Allocation failed!
4643 Allocation failed!
4648 Allocation failed!
4669 Allocation failed!
4696 Allocation failed!
4695 Allocation failed!
4716 Allocation failed!
4721 Allocation failed!

Nur 15 verarbeitet fehlgeschlagen 1 GB zuzuteilen - zeigt , daß die Heuristik für overcommit_memory = 0 wird von Zustand betroffen. Wie viele Prozesse gab es? Mit Blick auf das Ende von tmp.txt, wahrscheinlich> 100.000. Wie darf man nun eigentlich die 1 GB nutzen?

> cat tmp.txt | grep WROTE
4646 WROTE 1 GB
4648 WROTE 1 GB
4671 WROTE 1 GB
4687 WROTE 1 GB
4694 WROTE 1 GB
4696 WROTE 1 GB
4716 WROTE 1 GB
4721 WROTE 1 GB

Acht - was wieder Sinn macht, da ich zu der Zeit ~ 3 GB RAM frei und 6 GB Swap hatte.

Sehen Sie sich danach Ihre Systemprotokolle an. Sie sollten sehen, dass der OOM-Killer (unter anderem) Punkte meldet. vermutlich bezieht sich dies auf oom_badness.

Goldlöckchen
quelle
das austauschen ist keine lösung (oder auch nur eine beziehung) zu memory over commitment. Bei der Speicherzuweisung (z. B. malloc) wird angefordert, dass virtueller Speicher reserviert wird, nicht physischer.
Juli
1
@ jillagre: "Auslagern ist keine Lösung (oder auch nur im Zusammenhang damit), dass der Speicher über dem Commitment liegt" -> Ja, eigentlich ist es das. Wenig genutzte Seiten werden aus dem RAM ausgelagert, wodurch mehr RAM zur Verfügung steht, um Seitenfehler zu beheben, die durch Paging / Allokation bei Bedarf verursacht werden (dies ist der Mechanismus, der eine Überbindung ermöglicht). Die ausgelagerten Seiten müssen möglicherweise irgendwann erneut in den Arbeitsspeicher ausgelagert werden.
Goldlöckchen
"Bei der Speicherzuweisung (zB: malloc) geht es darum, dass der virtuelle Speicher reserviert wird, nicht der physische." -> Richtig, aber der Kernel könnte (und wird optional) nein sagen, wenn keine physischen Zuordnungen mehr vorhanden sind. Dies liegt sicherlich nicht daran, dass einem Prozess der virtuelle Adressraum ausgegangen ist (oder zumindest normalerweise nicht, da dies zumindest auf 32-Bit-Systemen ebenfalls möglich ist).
Goldlöckchen
Demand Paging ist nicht das, was Speicher über Commitment ermöglicht. Linux hat auf Systemen ohne Swap-Bereich mit Sicherheit überlastet. Möglicherweise verwechseln Sie den Speicher mit dem Commitment und fordern Paging an. Wenn Linux mit einem 64-Bit-Prozess "Nein" zu malloc sagt, dh wenn es nicht so konfiguriert ist, dass immer ein Overcommit ausgeführt wird, liegt dies entweder an einer Speicherbeschädigung oder an der Summe aller Speicherreservierungen (egal ob RAM oder Festplatte zugeordnet). liegt je nach Konfiguration über einem Schwellenwert. Dies hat nichts mit der RAM-Auslastung zu tun, da dies auch dann passieren kann, wenn noch RAM frei ist.
Juli
"Demand Paging ist nicht das, was Speicher über Commitment ermöglicht." -> Vielleicht ist es besser zu sagen, dass es sich um eine virtuelle Adressierung handelt, die sowohl das Paging von Nachfragen als auch eine Überbindung ermöglicht. "Linux hat auf Systemen ohne Swap-Bereich mit Sicherheit übermäßig viel Speicher belegt." -> Offensichtlich, da Demand Paging keinen Swap erfordert; Demand Paging von Swap ist nur eine spezielle Instanz von Demand Paging. Wieder einmal Swap ist eine Lösung über Engagement, nicht in dem Sinne , dass es das Problem löst, sondern in dem Sinne , dass potenzielle OOM Ereignisse zu verhindern , wird dazu beitragen , die von über Engagement führen könnte.
Goldlöckchen
16

Dies passiert Ihnen nicht, wenn Sie nur 1 GB Daten in den Speicher laden. Was ist, wenn Sie viel, viel mehr laden? Zum Beispiel arbeite ich oft mit riesigen Dateien, die Millionen von Wahrscheinlichkeiten enthalten, die in R geladen werden müssen. Dies benötigt ungefähr 16 GB RAM.

Das Ausführen des obigen Vorgangs auf meinem Laptop führt dazu, dass es wie verrückt wechselt, sobald meine 8 GB RAM voll sind. Dies wiederum verlangsamt alles, da das Lesen von der Festplatte viel langsamer ist als das Lesen aus dem RAM. Was ist, wenn ich einen Laptop mit 2 GB RAM und nur 10 GB freiem Speicherplatz habe? Sobald der Prozess den gesamten Arbeitsspeicher belegt hat, füllt er auch den Datenträger, da es sich um einen Schreibvorgang zum Auslagern handelt und mir kein Arbeitsspeicher und kein Speicherplatz mehr zum Auslagern verbleibt (Benutzer beschränken den Auslagerungsvorgang in der Regel eher auf eine dedizierte Partition als auf eine Swap-Datei aus genau diesem Grund). Hier kommt der OOM-Killer ins Spiel und beginnt Prozesse zu töten.

Dem System kann also tatsächlich der Speicher ausgehen. Darüber hinaus können stark vertauschte Systeme unbrauchbar werden, lange bevor dies einfach aufgrund der langsamen E / A-Operationen aufgrund des Austauschs geschieht. Man möchte generell vermeiden, so viel wie möglich zu tauschen. Selbst auf High-End-Servern mit schnellen SSDs ist ein deutlicher Leistungsabfall zu verzeichnen. Auf meinem Laptop, der über ein klassisches Laufwerk mit 7200 U / min verfügt, wird das System durch signifikantes Austauschen im Wesentlichen unbrauchbar. Je mehr es tauscht, desto langsamer wird es. Wenn ich den Prozess nicht schnell abbringe, bleibt alles hängen, bis der OOM-Killer einspringt.

terdon
quelle
5

Prozesse werden nicht abgebrochen, wenn kein RAM mehr vorhanden ist. Sie werden abgebrochen, wenn sie auf folgende Weise betrogen wurden:

  • Mit dem Linux-Kernel können Prozesse normalerweise eine größere Menge an virtuellem Speicher zuweisen (dh reservieren), als tatsächlich verfügbar ist (Teil des Arbeitsspeichers + der gesamte Swap-Bereich).
  • Solange die Prozesse nur auf eine Teilmenge der von ihnen reservierten Seiten zugreifen, funktioniert alles einwandfrei.
  • Wenn ein Prozess nach einiger Zeit versucht, auf eine Seite zuzugreifen, die ihm gehört, aber keine weiteren Seiten mehr frei sind, tritt eine Situation mit unzureichendem Speicher auf
  • Der OOM-Killer wählt einen der Prozesse aus, nicht unbedingt den, der eine neue Seite angefordert hat, und beendet sie einfach, um den virtuellen Speicher wiederherzustellen.

Dies kann auch passieren, wenn das System nicht aktiv austauscht, z. B. wenn der Auslagerungsbereich mit Speicherseiten für Sleeping Daemons gefüllt ist.

Dies geschieht niemals bei Betriebssystemen, bei denen der Speicher nicht überlastet wird. Bei ihnen wird kein zufälliger Prozess beendet, aber der erste Prozess, der nach virtuellem Speicher fragt, während er erschöpft ist, führt zu einer fehlerhaften Rückkehr von malloc (oder ähnlichem). Es wird somit eine Chance gegeben, die Situation richtig zu handhaben. Unter diesen Betriebssystemen kann es jedoch auch vorkommen, dass dem System der virtuelle Speicher ausgeht, solange noch freier Arbeitsspeicher vorhanden ist. Dies ist ziemlich verwirrend und wird im Allgemeinen missverstanden.

jlliagre
quelle
3

Wenn der verfügbare RAM erschöpft ist, beginnt der Kernel, Verarbeitungsbits auf die Festplatte auszutauschen. Tatsächlich beginnt der Kernel mit dem Auslagern eines Arbeitsspeichers, wenn der Arbeitsspeicher nahezu erschöpft ist: Er beginnt mit dem proaktiven Auslagern, wenn ein Leerlauf vorliegt, um reaktionsschneller zu sein, wenn eine Anwendung plötzlich mehr Arbeitsspeicher benötigt.

Beachten Sie, dass der RAM nicht nur zum Speichern des Speichers von Prozessen verwendet wird. Auf einem typischen fehlerfreien System wird nur etwa die Hälfte des Arbeitsspeichers von Prozessen und die andere Hälfte für Festplatten-Cache und Puffer verwendet. Dies bietet ein ausgewogenes Verhältnis zwischen laufenden Prozessen und Dateieingabe / -ausgabe.

Der Swap Space ist nicht unendlich. Wenn Prozesse immer mehr Speicher zuweisen, füllen die Überlaufdaten aus dem RAM den Swap. In diesem Fall wird den Prozessen, die versuchen, mehr Speicher anzufordern, die Anforderung verweigert.

Standardmäßig überlastet Linux den Speicher. Dies bedeutet, dass ein Prozess manchmal mit reserviertem, aber nicht verwendetem Speicher ausgeführt werden kann. Der Hauptgrund für die Überbindung ist die Art und Weise, wie das Gabeln funktioniert. Wenn ein Prozess einen Unterprozess startet, wird der untergeordnete Prozess konzeptionell in einer Replik des Speichers des übergeordneten Prozesses ausgeführt. Die beiden Prozesse verfügen anfangs über Speicher mit demselben Inhalt, dieser Inhalt wird jedoch divergieren, da die Prozesse jeweils Änderungen in ihrem eigenen Bereich vornehmen. Um dies vollständig zu implementieren, müsste der Kernel den gesamten Speicher des übergeordneten Elements kopieren. Dies würde das Gabeln langsam machen, so dass der Kernel das Kopieren beim Schreiben übt: anfangs teilt das Kind sein gesamtes Gedächtnis mit dem Elternteil; Wenn ein Prozess auf eine freigegebene Seite schreibt, erstellt der Kernel eine Kopie dieser Seite, um die Freigabe zu unterbrechen.

Oft lässt ein Kind viele Seiten unberührt. Wenn der Kernel genügend Speicherplatz zuweist, um den Speicherplatz des übergeordneten Elements auf jedem Zweig zu replizieren, würde viel Speicher für Reservierungen verschwendet, die untergeordnete Prozesse niemals verwenden werden. Überlastung: Der Kernel reserviert nur einen Teil dieses Speichers, basierend auf einer Schätzung, wie viele Seiten das Kind benötigen wird.

Wenn ein Prozess versucht, Speicher zuzuweisen, und nicht genügend Speicher verfügbar ist, erhält der Prozess eine Fehlerantwort und verarbeitet sie nach eigenem Ermessen. Wenn ein Prozess indirekt Speicher anfordert, indem er auf eine freigegebene Seite schreibt, deren Freigabe aufgehoben werden muss, ist dies eine andere Geschichte. Es gibt keine Möglichkeit, diese Situation der Anwendung mitzuteilen: Sie geht davon aus, dass sie dort beschreibbare Daten hat und diese sogar lesen kann. Das Schreiben erfordert lediglich etwas aufwendigere Operationen unter der Haube. Wenn der Kernel keine neue Speicherseite bereitstellen kann, kann er nur den anfordernden Prozess oder einen anderen Prozess beenden, um den Speicher zu füllen.

Sie könnten an dieser Stelle denken, dass das Beenden des Anforderungsprozesses die naheliegende Lösung ist. In der Praxis ist dies jedoch nicht so gut. Der Prozess kann ein wichtiger sein, der nur auf eine seiner Seiten zugreifen muss, während möglicherweise andere, weniger wichtige Prozesse ausgeführt werden. Daher enthält der Kernel komplexe Heuristiken, um zu entscheiden, welche Prozesse beendet werden sollen - den (in) berühmten OOM-Killer .

Gilles 'SO - hör auf böse zu sein'
quelle
2

Um einen anderen Gesichtspunkt aus den anderen Antworten hinzuzufügen, hosten viele VPS mehrere virtuelle Maschinen auf einem bestimmten Server. Jede einzelne VM verfügt über eine bestimmte Menge an RAM für den eigenen Gebrauch. Viele Anbieter bieten "Burst-RAM" an, bei dem sie RAM über die von ihnen festgelegte Menge hinaus verwenden können. Dies ist nur für den kurzfristigen Gebrauch gedacht, und diejenigen, die über diesen längeren Zeitraum hinausgehen, werden möglicherweise vom Host bestraft, indem er Prozesse abbricht, um die Menge des verwendeten Arbeitsspeichers zu verringern, damit andere nicht darunter leiden Die Host-Maschine ist überlastet.

agweber
quelle
-1

Einige Zeit benötigt Linux externen virtuellen Raum. Das ist die Swap-Partition. Wenn Ram gefüllt ist, verwendet Linux diesen Swap-Bereich, um den Prozess mit niedriger Priorität auszuführen.

Bizzon
quelle
1
Es ist kein Verfahren läuft aus Swap. Der virtuelle Speicher ist in gleich große separate Einheiten unterteilt, die als Seiten bezeichnet werden. Wenn physischer Speicher freigegeben wird, werden Seiten mit niedriger Priorität aus dem RAM entfernt. Während Seiten im Dateicache eine Dateisystemunterstützung haben, müssen anonyme Seiten im Swap gespeichert werden. Die Priorität einer Seite hängt nicht direkt von der Priorität des Prozesses ab, zu dem sie gehört, sondern davon, wie oft sie verwendet wird. Wenn ein laufender Prozess versucht, auf eine Seite zuzugreifen, die sich nicht im physischen Speicher befindet, wird ein Seitenfehler generiert, und der Prozess wird zugunsten eines anderen Prozesses vorgezogen , während die benötigten Seiten von der Festplatte abgerufen werden.
Thomas Nyman