Linux inizierà a uccidere i miei processi senza chiedermi se la memoria si esaurisce?


66

Stavo eseguendo uno script di shell con comandi per eseguire diversi programmi ad alta intensità di memoria (2-5 GB) back-to-back. Quando sono tornato a controllare lo stato di avanzamento della mia sceneggiatura, sono stato sorpreso di scoprire che alcuni dei miei processi erano Killed, come mi ha riferito il mio terminale. Diversi programmi erano già stati completati successivamente prima dei programmi che erano stati successivamente Killedavviati, ma in seguito tutti i programmi hanno fallito in un errore di segmentazione (che potrebbe essere stato o meno a causa di un bug nel mio codice, continua a leggere).

Ho esaminato la cronologia di utilizzo del particolare cluster che stavo usando e ho visto che qualcuno ha iniziato a eseguire diversi processi ad alta intensità di memoria contemporaneamente e nel farlo ha esaurito la memoria reale (e possibilmente anche lo spazio di scambio) disponibile per il cluster. Per quanto riesco a immaginare, questi processi ad alta intensità di memoria hanno iniziato a funzionare nello stesso momento in cui ho iniziato ad avere problemi con i miei programmi.

È possibile che Linux abbia ucciso i miei programmi una volta che ha esaurito la memoria? Ed è possibile che gli errori di segmentazione che ho riscontrato in seguito fossero dovuti alla mancanza di memoria disponibile per eseguire i miei programmi (anziché un bug nel mio codice)?


2
Quando si alloca memoria, si dispone di un'istruzione per verificare se la memoria è stata allocata correttamente? Ciò dovrebbe fornire un indizio sull'eventuale presenza di bug nel codice o sulla mancanza di memoria nel sistema.
Unxnut

Risposte:


72

Può.

Esistono due diverse condizioni di memoria insufficiente che è possibile riscontrare in Linux. Che incontri dipende dal valore di sysctl vm.overcommit_memory( /proc/sys/vm/overcommit_memory)

Introduzione:
il kernel può eseguire quello che viene chiamato 'overcommit di memoria'. Questo è quando il kernel assegna ai programmi più memoria di quanta ne sia realmente presente nel sistema. Questo viene fatto nella speranza che i programmi non utilizzino effettivamente tutta la memoria che hanno allocato, poiché si tratta di un evento abbastanza comune.

overcommit_memory = 2

Quando overcommit_memoryè impostato su 2, il kernel non esegue alcun overcommit. Invece quando un programma è allocato in memoria, è garantito l'accesso per avere quella memoria. Se il sistema non ha abbastanza memoria libera per soddisfare una richiesta di allocazione, il kernel restituirà semplicemente un errore per la richiesta. Spetta al programma gestire con garbo la situazione. Se non verifica che l'allocazione abbia avuto esito positivo quando ha avuto esito negativo, l'applicazione riscontrerà spesso un segfault.

Nel caso del segfault, dovresti trovare una linea come questa nell'output di dmesg:

[1962.987529] myapp[3303]: segfault at 0 ip 00400559 sp 5bc7b1b0 error 6 in myapp[400000+1000]

Ciò at 0significa che l'applicazione ha tentato di accedere a un puntatore non inizializzato, che può essere il risultato di una chiamata di allocazione della memoria non riuscita (ma non è l'unico modo).

overcommit_memory = 0 e 1

Quando overcommit_memoryè impostato su 0o 1, l'overcommit è abilitato e ai programmi è consentito allocare più memoria di quella realmente disponibile.

Tuttavia, quando un programma vuole usare la memoria che è stata allocata, ma il kernel scopre che in realtà non ha memoria sufficiente per soddisfarla, deve recuperare un po 'di memoria. Tenta innanzitutto di eseguire varie attività di pulizia della memoria, come svuotare le cache, ma se ciò non bastasse, termina un processo. Questa terminazione viene eseguita da OOM-Killer. OOM-Killer guarda il sistema per vedere quali programmi utilizzano quale memoria, da quanto tempo sono in esecuzione, chi li sta eseguendo e una serie di altri fattori per determinare quale viene ucciso.

Dopo che il processo è stato terminato, la memoria che stava usando viene liberata e il programma che ha causato la condizione di memoria insufficiente ora ha la memoria di cui ha bisogno.

Tuttavia, anche in questa modalità, è ancora possibile rifiutare le richieste di allocazione ai programmi. Quando overcommit_memoryè 0, il kernel prova a indovinare quando dovrebbe iniziare a negare le richieste di allocazione. Quando è impostato su 1, non sono sicuro di quale determinazione usi per determinare quando deve rifiutare una richiesta ma può rifiutare richieste molto grandi.

Puoi vedere se OOM-Killer è coinvolto guardando l'output di dmesge trovando un messaggio come:

[11686.043641] Out of memory: Kill process 2603 (flasherav) score 761 or sacrifice child
[11686.043647] Killed process 2603 (flasherav) total-vm:1498536kB, anon-rss:721784kB, file-rss:4228kB

Quindi, sembra che entrambe le situazioni mi siano successe.
NeutronStar

@Joshua Ho appena aggiornato la risposta. Ho dimenticato di menzionare che è ancora possibile ottenere errori di allocazione quando overcommit_memoryè impostato su 0 o 2.
Patrick,

Penso che valga la pena modificare un link per domare il killer OOM nel post.
0xC0000022L

@ 0xC0000022L Grazie, è un buon articolo (anche se un po 'obsoleto). Non volevo fare nulla per controllare il killer OOM dal momento che non fa parte della domanda (e non è un argomento breve), e abbiamo un sacco di altre domande qui proprio su questo.
Patrick,

1
@mikeserv Non dico che il comportamento del killer OOM non abbia nulla a che fare con il controllo. La domanda era se Linux avrebbe ucciso i suoi programmi. Come evitare che Linux lo faccia prima, è necessario stabilire che lo sta effettivamente facendo Linux. E se overcommit_memory=2, il killer OOM non è nemmeno abilitato, quindi controllarlo è irrilevante. Tuttavia, una volta stabilito che è il killer OOM, che diventa un altro argomento in cui è coperto da molte altre domande e risposte qui.
Patrick,

16

La verità è che, indipendentemente dal modo in cui lo guardi, sia che il tuo processo sia bloccato a causa del gestore della memoria del sistema o per qualcos'altro, è ancora un bug. Che cosa è successo a tutti quei dati che stavi elaborando in memoria? Avrebbe dovuto essere salvato.

Mentre overcommit_memory=è il modo più generale di configurare la gestione OOM di Linux, è anche regolabile per processo come:

echo [-+][n] >/proc/$pid/oom_adj

L'uso -17di quanto sopra esclude un processo dalla gestione della memoria insufficiente. Probabilmente non è una grande idea in generale, ma se stai cercando un bug, potrebbe valerne la pena, specialmente se desideri sapere se era OOM o il tuo codice. Incrementare positivamente il numero renderà più probabile che il processo venga ucciso in un evento OOM, il che potrebbe consentire di sostenere meglio la resilienza del codice in situazioni di memoria insufficiente e di assicurarti di uscire con garbo quando necessario.

È possibile controllare le impostazioni correnti del gestore OOM per processo come:

cat /proc/$pid/oom_score 

Altrimenti potresti suicidarti:

sysctl vm.panic_on_oom=1
sysctl kernel.panic=X

Ciò imposterà il riavvio del computer in caso di una condizione di memoria insufficiente. Impostare quanto Xsopra sul numero di secondi in cui si desidera arrestare il computer dopo un panico del kernel prima di riavviare. Vai selvaggio.

E se, per qualche motivo, decidi che ti piace, rendilo persistente:

echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
echo "kernel.panic=X" >> /etc/sysctl.conf

È un cluster condiviso che sto usando, sono sicuro che gli altri utenti non apprezzerebbero il riavvio senza il loro consenso.
NeutronStar

3
@Joshua - Dubito molto seriamente che a qualcuno piacerebbe - anche sfidando le leggi della robotica di Asimov. D'altra parte, come ho già detto, è possibile configurare OOM per processo anche nell'altro modo. Vale a dire che è possibile eseguire il triage personale in base alle proprie regole definite per processo. Questo genere di cose sembra essere particolarmente utile in uno scenario di cluster condiviso.
Mikeserv,
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.