Il assassino di OOM o Memoria insufficiente Killer è un processo che
linux kernel utilizza quando il sistema ha poca memoria. … Ciò massimizza l'uso della memoria di sistema assicurando che la
memoria allocata ai processi venga utilizzata attivamente.
Questa domanda con risposta automatica chiede:
- Come testare oom-killer dalla riga di comando?
Sarebbe accettato un metodo più rapido di 1/2 ora necessaria per la risposta automatica.
Risposta accettata:
La chiave per attivare rapidamente il killer OOM è evitare di impantanarsi negli accessi al disco. Quindi:
-
Evita lo scambio, a meno che il tuo obiettivo non sia specificamente quello di testare il comportamento di OOM quando viene utilizzato lo scambio. Puoi disabilitare lo scambio prima del test, quindi riattivarlo in seguito.
swapon -s
ti dice quali scambi sono attualmente abilitati.sudo swapoff -a
disabilita tutti gli scambi;sudo swapon -a
di solito è sufficiente per riattivarli. -
Evita di disperdere gli accessi alla memoria con accessi al disco non di swap. Quel metodo basato sul globbing alla fine consuma la tua memoria disponibile (dato un numero sufficiente di voci nel tuo filesystem), ma il motivo per cui ha bisogno di così tanta memoria è per memorizzare le informazioni che ottiene accedendo al tuo filesystem. Anche con un SSD, è probabile che gran parte del tempo venga dedicato alla lettura dal disco, anche se lo scambio è disattivato. Se il tuo obiettivo è specificamente quello di testare il comportamento OOM per gli accessi alla memoria intervallati da accessi al disco, quel metodo è ragionevole, forse anche ideale. Altrimenti, puoi raggiungere il tuo obiettivo molto più velocemente.
Dopo aver disabilitato lo scambio, qualsiasi metodo che legge raramente da un disco fisico dovrebbe essere abbastanza veloce. Questo include tail /dev/zero
(trovato da falstaff, commentato sopra da Doug Smythies). Anche se legge dal dispositivo di caratteri /dev/zero
, quel "dispositivo" genera semplicemente byte nulli (ovvero, byte di tutti zeri) e non implica alcun accesso al disco fisico una volta che il nodo del dispositivo è stato aperto. Questo metodo funziona perché tail
cerca le righe finali nel suo input, ma un flusso di zeri non contiene caratteri di nuova riga, quindi non ottiene mai righe da scartare.
Se stai cercando un one-liner in un linguaggio interpretato che alloca e popola la memoria in modo algoritmico, sei fortunato. In quasi tutti i linguaggi interpretati per uso generico, è facile allocare molta memoria e scrivervi senza altrimenti utilizzarla. Ecco una riga di Perl che sembra essere veloce quanto tail /dev/zero
(anche se non l'ho confrontato ampiamente):
perl -wE 'my @xs; for (1..2**20) { push @xs, q{a} x 2**20 }; say scalar @xs;'
Con lo scambio disattivato su una vecchia macchina con 4 GiB di RAM, sia quello che tail /dev/zero
ci sono voluti circa dieci secondi ogni volta che li ho eseguiti. Entrambi dovrebbero comunque funzionare bene su macchine più recenti con molta più RAM di quella. Puoi farlo perl
comando molto più breve, se il tuo obiettivo è la brevità.
Che Perl one-liner genera ripetutamente (q{a} x 2**20
) separa stringhe moderatamente lunghe, circa un milione di caratteri ciascuna, e le mantiene tutte intorno memorizzandole in un array (@xs
). È possibile regolare i numeri per il test. Se non si utilizza tutta la memoria disponibile, one-liner restituisce il numero totale di stringhe create. Supponendo che il killer OOM uccida perl
–con il comando esatto mostrato sopra e nessuna quota di risorse da intralciare, credo che in pratica lo farà sempre–quindi la tua shell dovrebbe mostrarti Killed
. Quindi, come in ogni situazione OOM, dmesg
ha i dettagli.
Anche se mi piace quel metodo, illustra qualcosa di utile sulla scrittura, la compilazione e l'utilizzo di un programma C, come quello nella risposta di Doug Smythies. L'allocazione della memoria e l'accesso alla memoria non sembrano cose separate nei linguaggi interpretati di alto livello, ma in C puoi notare e, se lo desideri, investigare quei dettagli.
Infine, dovresti sempre verificare che il killer OOM sia effettivamente ciò che ha ucciso il tuo programma . Un modo per controllare è ispezionare dmesg
. Contrariamente alla credenza popolare, è effettivamente possibile che un tentativo di allocare memoria fallisca rapidamente, anche su Linux. È facile farlo accadere con enormi allocazioni che ovviamente falliranno... ma anche quelle possono accadere inaspettatamente. E le allocazioni apparentemente ragionevoli potrebbero fallire rapidamente. Ad esempio, sulla mia macchina di prova, perl -wE 'say length q{a} x 3_100_000_000;'
riesce e perl -wE 'say length q{a} x 3_200_000_000;'
stampe:
Out of memory!
panic: fold_constants JMPENV_PUSH returned 2 at -e line 1.
Nessuno dei due ha innescato il killer OOM. Parlando più in generale:
- Se il tuo programma calcola in anticipo quanta memoria è necessaria e la richiede in un'unica allocazione, l'allocazione potrebbe avere esito positivo (e in tal caso, il killer OOM potrebbe o meno uccidere il programma quando viene utilizzata una quantità sufficiente di memoria), o l'allocazione potrebbe semplicemente fallire.
- Espandere un array a una lunghezza enorme aggiungendo molti, molti elementi ad esso spesso attiva il killer OOM nella pratica, ma facendolo farlo in modo affidabile nei test è sorprendentemente complicato. Il modo in cui questo viene quasi sempre fatto, perché è il modo più efficiente per farlo, è creare ogni nuovo buffer con una capacità x volte la capacità del vecchio buffer. Valori comuni per x includere 1.5 e 2 (e la tecnica è spesso chiamata "raddoppio del tavolo"). Questo a volte colma il divario tra quanta memoria può essere effettivamente allocata e utilizzata e quanto il kernel sa essere troppo per preoccuparsi persino di fingere di distribuire.
- Le allocazioni di memoria possono fallire per motivi che hanno poco a che fare con il kernel o la quantità di memoria effettivamente disponibile, e questo non attiva nemmeno il killer OOM. In particolare, un programma potrebbe fallire rapidamente su un'allocazione di qualsiasi dimensione dopo aver eseguito con successo un numero molto elevato di piccole allocazioni. Questo errore si verifica nella contabilità che viene eseguita dal programma stesso, di solito attraverso una struttura di libreria come
malloc()
. Sospetto che questo sia quello che mi è successo oggi quando, durante i test conbash
array (che in realtà sono implementati come liste doppiamente collegate),bash
uscire con un messaggio di errore che dice un'allocazione di 9 byte fallito.
Il killer OOM è molto più facile da attivare accidentalmente che da attivare intenzionalmente.
Nel tentativo di attivare deliberatamente il killer OOM, un modo per aggirare questi problemi è iniziare richiedendo troppa memoria e ridursi gradualmente, come fa il programma C di Doug Smythies. Un altro modo è allocare un intero gruppo di blocchi di memoria di dimensioni moderate, che è ciò che fa la riga di Perl mostrata sopra:nessuna delle stringhe di caratteri milionari (più un po' di utilizzo di memoria aggiuntivo dietro le quinte) è particolarmente faticoso, ma presi insieme, tutti gli acquisti da un megabyte si sommano.