Linux può "rimanere senza RAM"?


20

Ho visto diversi post sulla rete di persone che apparentemente si lamentavano di un VPS ospitato che inaspettatamente uccideva i processi perché usavano troppa RAM.

Com'è possibile? Pensavo che tutti i moderni sistemi operativi fornissero "RAM infinita" semplicemente usando lo swap del disco per qualunque cosa si sovrapponga alla RAM fisica. È corretto?

Cosa potrebbe accadere se un processo viene "interrotto a causa della RAM bassa"?


12
Nessun sistema operativo ha RAM infinita . Oltre ai chip RAM fisici della macchina, i sistemi operativi possono - di solito, facoltativamente - utilizzare un cosiddetto "file di scambio" che si trova sul disco. Quando un computer ha bisogno di più memoria di quella contenuta nelle chiavette RAM, scambia alcune cose con il file di scambio. Ma quando il file di scambio raggiunge la sua capacità - o perché hai impostato una dimensione massima (tipica) o il disco si riempie - esaurisci la memoria virtuale.
John Dibling,

@JohnDibling; quindi c'è qualche motivo per cui si vorrebbe limitare la dimensione dello swap oltre a risparmiare spazio su disco per il filesystem? In altre parole, se ho un disco da 20 GB e solo 1 GB di file, c'è qualche motivo per non impostare la mia dimensione di scambio su 19 GB?
themirror

1
Per semplificare eccessivamente le cose, direi che i due motivi per limitare le dimensioni dello swap sono 1) per ridurre il consumo del disco e 2) per aumentare le prestazioni. Quest'ultimo potrebbe essere più vero in Windows rispetto a / * NIX, ma, di nuovo, se si utilizza lo spazio di swap sul disco, le prestazioni sono ridotte. L'accesso al disco è più lento della RAM o molto più lento della RAM, a seconda del sistema.
John Dibling,

9
Lo scambio non è RAM . it.wikipedia.org/wiki/Random-access_memory La quantità di RAM nel tuo sistema è la quantità di RAM nel tuo sistema - periodo. Non è un volume ambiguo o dinamico. È assolutamente risolto. "Memoria" è un concetto più ambiguo, ma la distinzione tra RAM e altre forme di archiviazione è, come sottolinea terdon (+1), piuttosto significativa. Lo scambio del disco non può sostituire le prestazioni della RAM con molti ordini di grandezza . Un sistema che dipende eccessivamente dallo swap è nella migliore delle ipotesi temporaneo e in generale: immondizia.
Riccioli d'oro,

1
Quindi lo spazio su disco è infinito adesso?
Kaz,

Risposte:


41

Cosa potrebbe accadere se un processo viene "interrotto a causa della RAM bassa"?

Talvolta si dice che Linux per impostazione predefinita non rifiuta mai le richieste di più memoria dal codice dell'applicazione, ad es malloc(). 1 Questo non è in realtà vero; il valore predefinito utilizza un'euristica per cui

Vengono rifiutati evidenti sovraccarichi di spazio degli indirizzi. Utilizzato per un sistema tipico. Assicura che un'allocazione seria non riesce, consentendo al contempo un sovraccarico per ridurre l'utilizzo degli swap.

Da [linux_src]/Documentation/vm/overcommit-accounting(tutte le virgolette provengono dall'albero 3.11). Ciò che conta come "allocazione seriamente selvaggia" non è reso esplicito, quindi dovremmo esaminare la fonte per determinare i dettagli. Potremmo anche utilizzare il metodo sperimentale nella nota 2 (di seguito) per cercare di ottenere un riflesso dell'euristico - in base a ciò, la mia osservazione empirica iniziale è che in circostanze ideali (== il sistema è inattivo), se non si " Non hai alcuno swap, ti sarà permesso di allocare circa la metà della tua RAM, e se hai lo swap, otterrai circa la metà della tua RAM più tutto lo swap. Questo è più o meno per processo (ma nota che questo limite è dinamico e soggetto a cambiamenti a causa dello stato, vedi alcune osservazioni nella nota 5).

La metà della RAM più swap è esplicitamente il valore predefinito per il campo "CommitLimit" in /proc/meminfo. Ecco cosa significa - e nota che in realtà non ha nulla a che fare con il limite appena discusso (da [src]/Documentation/filesystems/proc.txt):

CommitLimit: basato sul rapporto di sovraccarico ('vm.overcommit_ratio'), questa è la quantità totale di memoria attualmente disponibile da allocare sul sistema. Questo limite viene rispettato solo se è abilitata la contabilità per sovraccarico rigoroso (modalità 2 in "vm.overcommit_memory"). CommitLimit viene calcolato con la seguente formula: CommitLimit = ('vm.overcommit_ratio' * RAM fisica) + Swap Ad esempio, su un sistema con 1G di RAM fisica e 7G di swap con un 'vm.overcommit_ratio' di 30 produrrebbe un CommitLimit di 7.3G.

Il documento di contabilità di sovraccarico precedentemente citato afferma che il valore predefinito vm.overcommit_ratioè 50. Quindi, se si sysctl vm.overcommit_memory=2, è quindi possibile regolare vm.covercommit_ratio (con sysctl) e vedere le conseguenze. 3 La modalità predefinita, quando CommitLimitnon viene applicata e vengono rifiutati solo "evidenti sovraccarichi di spazio degli indirizzi", è quando vm.overcommit_memory=0.

Mentre la strategia di default ha un limite euristico per processo che impedisce la "allocazione seriamente selvaggia", lascia il sistema nel suo insieme libero di diventare seriamente selvaggio, allocazione saggia. 4 Ciò significa che a un certo punto può esaurire la memoria e dover dichiarare fallimento ad alcuni processi tramite il killer OOM .

Cosa uccide il killer OOM? Non necessariamente il processo che richiedeva memoria quando non ce n'era, dal momento che non è necessariamente il processo veramente colpevole, e, cosa più importante, non necessariamente quello che risolverà il sistema più rapidamente dal problema in cui si trova.

Questo è citato da qui che probabilmente cita una fonte 2.6.x:

/*
 * 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)
 */

Che sembra una logica decente. Tuttavia, senza essere forensi, il n. 5 (che è ridondante del n. 1) sembra un'implementazione di vendita dura e il n. 3 è ridondante del n. 2. Quindi potrebbe avere senso considerare questo ridotto a # 2/3 e # 4.

Ho esaminato una fonte recente (3.11) e ho notato che questo commento è cambiato nel frattempo:

/**
 * 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.
 */

Questo è un po 'più esplicitamente su # 2: "L'obiettivo è quello di [uccidere] l'attività che consuma più memoria per evitare successivi errori di oom", e di conseguenza # 4 ( "vogliamo uccidere la quantità minima di processi ( uno ) ) .

Se vuoi vedere il killer OOM in azione, vedi la nota 5.


1 Un'illusione di Gilles per fortuna mi libera di, vedi commenti.


2 Ecco un semplice bit di C che richiede blocchi di memoria sempre più grandi per determinare quando una richiesta di più fallirà:

#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;
}            

Se non conosci C, puoi compilare questo gcc virtlimitcheck.c -o virtlimitcheck, quindi eseguire ./virtlimitcheck. È completamente innocuo, poiché il processo non utilizza lo spazio richiesto, ovvero non utilizza mai RAM.

Su un sistema 3,11 x86_64 con sistema da 4 GB e 6 GB di scambio, ho fallito a ~ 7400000 kB; il numero fluttua, quindi forse lo stato è un fattore. Per coincidenza, questo è vicino a CommitLimitin /proc/meminfo, ma modificarlo tramite vm.overcommit_rationon fa alcuna differenza. Su un sistema ARM 448 MB da 3,6.11 a 32 bit con 64 MB di scambio, tuttavia, non riesco a ~ 230 MB. Questo è interessante poiché nel primo caso la quantità è quasi il doppio della quantità di RAM, mentre nel secondo è circa 1/4 che - implicando fortemente la quantità di swap è un fattore. Ciò è stato confermato disattivando lo swap sul primo sistema, quando la soglia di errore è scesa a ~ 1,95 GB, un rapporto molto simile alla piccola scatola ARM.

Ma è davvero per processo? Sembra essere. Il breve programma in basso richiede un pezzo di memoria definito dall'utente e, se riesce, attende che tu prema return - in questo modo puoi provare più istanze simultanee:

#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;
}

Attenzione, tuttavia, che non si tratta strettamente della quantità di RAM e di scambio indipendentemente dall'uso - vedere la nota 5 per osservazioni sugli effetti dello stato del sistema.


3 si CommitLimit riferisce alla quantità di spazio di indirizzi consentita per il sistema quando vm.overcommit_memory = 2. Presumibilmente quindi, la quantità che è possibile allocare dovrebbe essere quella meno ciò che è già stato impegnato, che apparentemente è il Committed_AScampo.

Un esperimento potenzialmente interessante che lo dimostra è quello di aggiungere #include <unistd.h>in cima a virtlimitcheck.c (vedi nota 2), e fork()subito prima del while()ciclo. Non è garantito che funzioni come descritto qui senza una noiosa sincronizzazione, ma c'è una buona possibilità che lo faccia, 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.

Questo ha senso - guardando in dettaglio tmp.txt è possibile vedere i processi alternare le loro allocazioni sempre più grandi (questo è più facile se si lancia il pid nell'output) fino a quando uno, evidentemente, ha affermato abbastanza che l'altro fallisce. Il vincitore è quindi libero di prendere tutto fino a CommitLimitmeno Committed_AS.


4 Vale la pena ricordare, a questo punto, se non si capisce già l'indirizzamento virtuale e il paging della domanda, in primo luogo ciò che rende possibile l'impegno eccessivo è che ciò che il kernel assegna ai processi della terra dell'utente non è affatto memoria fisica - è spazio di indirizzi virtuali . Ad esempio, se un processo riserva 10 MB per qualcosa, è strutturato come una sequenza di indirizzi (virtuali), ma quegli indirizzi non corrispondono ancora alla memoria fisica. Quando si accede a tale indirizzo, si verifica un errore di paginae quindi il kernel tenta di mapparlo sulla memoria reale in modo che possa memorizzare un valore reale. I processi di solito riservano molto più spazio virtuale di quanto effettivamente accedano, il che consente al kernel di utilizzare la RAM in modo più efficiente. Tuttavia, la memoria fisica è ancora una risorsa limitata e quando tutto è stato mappato allo spazio degli indirizzi virtuali, è necessario eliminare parte dello spazio degli indirizzi virtuali per liberare un po 'di RAM.


5 Prima un avvertimento : se provi questo vm.overcommit_memory=0, assicurati di salvare prima il tuo lavoro e chiudere tutte le applicazioni critiche, perché il sistema verrà bloccato per ~ 90 secondi e alcuni processi moriranno!

L'idea è di lanciare una bomba a forcella che scade dopo 90 secondi, con le forche che allocano lo spazio e alcune di esse scrivono grandi quantità di dati nella RAM, riferendosi nel frattempo a stderr.

#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);
        }
    }
}                        

Compila questo gcc forkbomb.c -o forkbomb. Innanzitutto, provalo con sysctl vm.overcommit_memory=2- probabilmente otterrai qualcosa del tipo:

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 questo ambiente, questo tipo di bomba a forcella non va molto lontano. Si noti che il numero in "dice N forcelle" non è il numero totale di processi, è il numero di processi nella catena / ramo che porta a quello.

Ora provalo con vm.overcommit_memory=0. Se si reindirizza stderr a un file, è possibile eseguire successivamente alcune analisi di base, ad esempio:

> 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!

Solo 15 processi non sono riusciti a allocare 1 GB, dimostrando che l'euristica di overcommit_memory = 0 è influenzata dallo stato. Quanti processi c'erano? Guardando la fine di tmp.txt, probabilmente> 100.000. Ora come si può effettivamente utilizzare 1 GB?

> 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

Otto - il che ha di nuovo senso, dato che all'epoca avevo ~ 3 GB di RAM libera e 6 GB di swap.

Dai un'occhiata ai log di sistema dopo aver fatto questo. Dovresti vedere i punteggi dei rapporti del killer OOM (tra le altre cose); presumibilmente questo riguarda oom_badness.


lo scambio non è una soluzione (o addirittura correlata) alla memoria rispetto all'impegno. L'allocazione di memoria (ad es. Malloc) riguarda la richiesta di prenotazione della memoria virtuale, non fisica.
jlliagre,

1
@jillagre: "lo scambio non è una soluzione (o addirittura correlata) alla memoria rispetto all'impegno" -> Sì, in realtà lo è. Le pagine utilizzate di rado vengono sostituite dalla RAM, lasciando più RAM disponibile per gestire gli errori di pagina causati dal paging / allocazione della domanda (che è il meccanismo che rende possibile l'impegno eccessivo). A un certo punto potrebbe anche essere necessario richiedere il paging della RAM nelle pagine scambiate.
Riccioli d'oro,

"L'allocazione della memoria (ad es. Malloc) riguarda la richiesta di prenotazione della memoria virtuale, non di quella fisica." -> Giusto, ma il kernel potrebbe (e facoltativamente, dirà) no quando non ci sono mappature fisiche rimaste. Certamente non lo sarebbe perché un processo ha esaurito lo spazio degli indirizzi virtuali (o almeno non di solito, poiché anche questo è possibile, almeno sui sistemi a 32 bit).
Riccioli d'oro,

Il paging della domanda non è ciò che rende possibile la memoria rispetto all'impegno. Linux sicuramente impegna la memoria su sistemi senza alcuna area di scambio. Potresti confondere la memoria con l'impegno e richiedere il paging. Se Linux dice "no" per eseguire il malloc con un processo a 64 bit, ovvero se non è configurato per il sovraccarico sempre, ciò sarebbe dovuto al danneggiamento della memoria o alla somma di tutte le riserve di memoria (mappate o meno su RAM o disco) supera una soglia in base alla configurazione. Questo non ha nulla a che fare con l'utilizzo della RAM in quanto potrebbe accadere anche quando c'è ancora RAM libera.
jlliagre,

"Il paging della domanda non è ciò che rende possibile la memoria rispetto all'impegno."-> Forse sarebbe meglio dire che è l'indirizzamento virtuale che rende possibile sia il paging della domanda sia l'impegno eccessivo. "Linux sicuramente impegna la memoria su sistemi senza alcuna area di scambio." -> Ovviamente, poiché il paging della domanda non richiede swap; il paging della domanda da swap è solo un'istanza speciale del paging della domanda. Ancora una volta, lo swap è una soluzione per l'impegno eccessivo, non nel senso che risolve il problema, ma nel senso che aiuterà a prevenire potenziali eventi OOM che potrebbero derivare da un impegno eccessivo.
Riccioli d'oro,

16

Questo non ti succederà se carichi solo 1G di dati in memoria. E se carichi molto di più? Ad esempio, lavoro spesso con file di grandi dimensioni contenenti milioni di probabilità che devono essere caricati in R. Questo richiede circa 16 GB di RAM.

L'esecuzione del processo sopra descritto sul mio laptop farà sì che inizi a scambiare come un matto non appena i miei 8 GB di RAM sono stati riempiti. Ciò, a sua volta, rallenterà tutto perché la lettura dal disco è molto più lenta della lettura dalla RAM. Cosa succede se ho un laptop con 2 GB di RAM e solo 10 GB di spazio libero? Una volta che il processo ha assorbito tutta la RAM, riempirà anche il disco perché sta scrivendo per scambiare e non ho più RAM e non c'è più spazio per scambiare (le persone tendono a limitare lo scambio a una partizione dedicata piuttosto che a una file di swap proprio per questo motivo). È qui che entra in gioco l'assassino OOM e inizia a uccidere i processi.

Quindi, il sistema può effettivamente esaurire la memoria. Inoltre, i sistemi di scambio pesante possono diventare inutilizzabili molto prima che ciò avvenga semplicemente a causa delle lente operazioni di I / O dovute allo scambio. Generalmente si vuole evitare lo scambio il più possibile. Anche su server di fascia alta con SSD veloci si registra un netto calo delle prestazioni. Sul mio laptop, che ha un classico disco 7200 RPM, qualsiasi scambio significativo rende essenzialmente il sistema inutilizzabile. Più scambia, più diventa lento. Se non uccido rapidamente il processo offensivo, tutto si blocca fino a quando il killer OOM non interviene.


5

I processi non vengono uccisi quando non c'è più RAM, vengono uccisi quando sono stati traditi in questo modo:

  • Il kernel Linux comunemente consente ai processi di allocare (cioè riservare) una quantità di memoria virtuale che è maggiore di ciò che è realmente disponibile (parte della RAM + tutta l'area di scambio)
  • fintanto che i processi accedono solo a un sottoinsieme delle pagine che hanno prenotato, tutto procede bene.
  • se dopo qualche tempo, un processo tenta di accedere a una pagina di sua proprietà ma non ci sono più pagine libere, si verifica una situazione di memoria insufficiente
  • Il killer OOM seleziona uno dei processi, non necessariamente quello che ha richiesto una nuova pagina, e lo uccide solo per recuperare memoria virtuale.

Ciò può accadere anche quando il sistema non sta scambiando attivamente, ad esempio se l'area di scambio è piena di pagine di memoria dei demoni dormienti.

Questo non accade mai su sistemi operativi che non sovraccaricano la memoria. Con loro nessun processo casuale viene ucciso ma il primo processo che richiede memoria virtuale mentre è esaurito ha malloc (o simile) che ritorna in errore. Viene quindi data la possibilità di gestire correttamente la situazione. Tuttavia, su questi sistemi operativi, potrebbe anche accadere che il sistema esaurisca la memoria virtuale mentre c'è ancora RAM libera, che è abbastanza confusa e generalmente fraintesa.


3

Quando la RAM disponibile è esaurita, il kernel inizia a scambiare i bit di elaborazione su disco. In realtà, il kernel inizia a scambiare a quando la RAM è quasi esaurita: inizia a scambiare in modo proattivo quando ha un momento di inattività, in modo da essere più reattivo se un'applicazione richiede improvvisamente più memoria.

Si noti che la RAM non viene utilizzata solo per archiviare la memoria dei processi. Su un tipico sistema sano, solo la metà della RAM viene utilizzata dai processi e l'altra metà viene utilizzata per la cache del disco e i buffer. Ciò fornisce un buon equilibrio tra i processi in esecuzione e l'input / output del file.

Lo spazio di swap non è infinito. Ad un certo punto, se i processi continuano a allocare sempre più memoria, i dati di spillover dalla RAM riempiranno lo scambio. Quando ciò accade, i processi che tentano di richiedere più memoria visualizzano la loro richiesta negata.

Per impostazione predefinita, Linux sovraccarica la memoria. Ciò significa che a volte consentirà a un processo di essere eseguito con la memoria che ha riservato, ma non utilizzato. Il motivo principale per cui il sovraccarico è il modo in cui funziona il fork . Quando un processo avvia un sottoprocesso, il processo figlio funziona concettualmente in una replica della memoria del genitore - i due processi inizialmente hanno memoria con lo stesso contenuto, ma quel contenuto divergerà man mano che i processi apportano modifiche ciascuno nel proprio spazio. Per implementarlo completamente, il kernel dovrebbe copiare tutta la memoria del genitore. Ciò renderebbe il fork lento, quindi il kernel si esercita in copia-scrittura-scrittura: inizialmente, il bambino condivide tutta la sua memoria con il genitore; ogni volta che uno dei processi scrive su una pagina condivisa, il kernel crea una copia di quella pagina per interrompere la condivisione.

Spesso un bambino lascia molte pagine intatte. Se il kernel allocasse memoria sufficiente per replicare lo spazio di memoria del genitore su ciascun fork, molta memoria verrebbe sprecata nelle riserve che i processi figlio non useranno mai. Di conseguenza, il commit eccessivo: il kernel riserva solo parte di quella memoria, in base a una stima di quante pagine saranno necessarie al bambino.

Se un processo tenta di allocare un po 'di memoria e non è rimasta memoria sufficiente, il processo riceve una risposta di errore e la gestisce come ritiene opportuno. Se un processo richiede indirettamente memoria scrivendo su una pagina condivisa che deve essere non condivisa, è una storia diversa. Non c'è modo di riportare questa situazione all'applicazione: crede di avere dati scrivibili lì e potrebbe persino leggerli - è solo che la scrittura implica un'operazione leggermente più elaborata sotto il cofano. Se il kernel non è in grado di fornire una nuova pagina di memoria, tutto ciò che può fare è terminare il processo di richiesta o uccidere qualche altro processo per riempire la memoria.

A questo punto potresti pensare che uccidere il processo di richiesta sia la soluzione ovvia. Ma in pratica, questo non è così buono. Il processo potrebbe essere importante per cui è necessario accedere solo a una delle sue pagine ora, mentre potrebbero esserci altri processi meno importanti in esecuzione. Quindi il kernel include euristiche complesse per scegliere quali processi uccidere - il (in) famoso killer OOM .


2

Solo per aggiungere un altro punto di vista dalle altre risposte, molti VPS ospitano diverse macchine virtuali su un determinato server. Ogni singola macchina virtuale avrà una quantità specificata di RAM per il proprio uso. Molti provider offrono "burst RAM", in cui possono utilizzare la RAM oltre la quantità designata. Questo è pensato per essere solo per un uso a breve termine e coloro che vanno oltre questo periodo di tempo prolungato possono essere penalizzati dall'host che uccide i processi per ridurre la quantità di RAM in uso in modo che gli altri non soffrano di il computer host è sovraccarico.


-1

Qualche volta Linux prende spazio virtuale esterno. Questa è la partizione di swap. Quando Ram è pieno, Linux prende quest'area di swap per eseguire processi a bassa priorità.


1
Nessun processo viene eseguito da swap. La memoria virtuale è divisa in unità distinte di uguali dimensioni chiamate pagine. Quando la memoria fisica viene liberata, le pagine a bassa priorità vengono eliminate dalla RAM. Mentre le pagine nella cache dei file hanno il backup del file system, le pagine anonime devono essere archiviate in swap. La priorità di una pagina non è direttamente correlata alla priorità del processo a cui appartiene, ma con quale frequenza viene utilizzata. Se un processo in esecuzione tenta di accedere a una pagina non nella memoria fisica, viene generato un errore di pagina e il processo viene annullato a favore di un altro processo mentre le pagine necessarie vengono recuperate dal disco.
Thomas Nyman,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.