È così che dovrebbe comportarsi il paging di Linux?


26

Quando il mio sistema Linux si avvicina al paging (ovvero, nel mio caso, 16 GB di RAM quasi piena, 16 GB di scambio completamente vuoti) se un nuovo processo X tenta di allocare un po 'di memoria, il sistema si blocca completamente. Cioè, fino a quando una quantità sproporzionata di pagine, (wrt la dimensione totale e la velocità delle richieste di allocazione di memoria di X) sono state scambiate. Si noti che non solo la GUI non risponde completamente, ma anche i servizi di base come sshd sono completamente bloccati.

Sono due pezzi di codice (dichiaratamente rozzo) che utilizzo per innescare questo comportamento in modo più "scientifico". Il primo ottiene due numeri x, y dalla riga di comando e procede all'allocazione e all'inizializzazione di più blocchi di y byte fino a quando non sono stati allocati più di x byte totali. E poi dorme solo a tempo indeterminato. Questo verrà utilizzato per portare il sistema sull'orlo del paging.

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

int main(int argc, char** argv) {
   long int max = -1;
   int mb = 0;
   long int size = 0;
   long int total = 0;
   char* buffer;

   if(argc > 1)
     {
       max = atol(argv[1]);
       size = atol(argv[2]);
     }
   printf("Max: %lu bytes\n", max);
   while((buffer=malloc(size)) != NULL && total < max) {
       memset(buffer, 0, size);
       mb++;
       total=mb*size;
       printf("Allocated %lu bytes\n", total);       
   }      
   sleep(3000000);
   return 0;
}

Il secondo pezzo di codice fa esattamente quello che fa il primo tranne che ha un sleep(1);diritto dopo il printf(non ripeterò l'intero codice). Questo verrà usato quando il sistema è sull'orlo del paging per farlo scambiare le pagine in modo "delicato", cioè richiedendo lentamente l'allocazione di nuovi blocchi di memoria (in modo che il sistema dovrebbe sicuramente essere in grado di scambiare pagine e tenere il passo con le nuove richieste).

Quindi, con i due pezzi di codice compilati, chiamiamo i rispettivi ex fasteater e sloweater, facciamo questo:

1) avvia la tua interfaccia grafica preferita (ovviamente non strettamente necessaria)

2) avviare alcuni mem / swap meter (es. watch -n 1 free)

3) avviare più istanze in fasteater x ycui x è dell'ordine dei gigabyte e y è dell'ordine dei megabyte. Fallo fino a quasi riempire il montone.

4) avvia un'istanza di sloweater x y, sempre dove x è dell'ordine dei gigabyte e y è dell'ordine dei megabyte.

Dopo il passaggio 4) ciò che dovrebbe accadere (e succede sempre per il mio sistema) è che, dopo aver esaurito il pistone, il sistema si bloccherà completamente. gui è bloccato sshd è bloccato ecc. MA, non per sempre! Dopo che sloweater ha terminato le sue richieste di allocazione, il sistema tornerà in vita (dopo minuti di blocco, non secondi ...) con questa situazione:

a) la ram è quasi piena

b) lo swap è anche al completo (ricorda, all'inizio era vuoto)

c) nessun intervento killer.

E nota che la partizione di swap è su un SSD. Quindi, il sistema sembra non essere in grado di spostare gradualmente le pagine dalla ram allo swap (presumibilmente dai fasteater che stanno solo dormendo) per fare spazio alle richieste lente (e di pochi megabyte) del sloweater.

Ora, qualcuno mi correggerà se sbaglio, ma questo non sembra il modo in cui un sistema moderno dovrebbe comportarsi in questa impostazione. Sembra comportarsi come i vecchi sistemi (waaaaay indietro) quando non c'era supporto per il paging e il sistema di memoria virtuale ha appena scambiato l'intero spazio di memoria di qualche processo anziché poche pagine.

Qualcuno può provare anche questo? E forse qualcuno che ha anche un sistema BSD.

AGGIORNAMENTO 1 Ho seguito i consigli di Mark Plotnick di seguito nei commenti e ho iniziato vmstat 1 >outprima di procedere con il test di paging. Puoi vedere il risultato qui sotto (ho tagliato l'intera parte iniziale dove viene riempito il ram senza coinvolgimento di swap):

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
0  0   6144 160792      8 272868    0    0     0     0  281 1839  1  0 99  0  0
0  0   6144 177844      8 246096    0    0     0     0  425 2300  1  1 99  0  0
0  0   6144 168528      8 246112    0    0    16     0  293 1939  1  0 99  0  0
0  0   6144 158320      8 246116    0    0     0     0  261 1245  0  0 100  0  0
2  0  10752 161624      8 229024    0 4820 17148  4820  845 3656  1  2 97  0  0
2  0  10752 157300      8 228096    0    0 88348     0 2114 8902  0  5 94  1  0
0  0  10752 176108      8 200052    0    0 108312     0 2466 9772  1  5 91  3  0
0  0  10752 170040      8 196780    0    0 17380     0  507 1895  0  1 99  0  0
0 10  10752 160436      8 191244    0    0 346872    20 4184 17274  1  9 64 26  0
0 29 12033856 152888      8 116696 5992 15916880 1074132 15925816 819374 2473643  0 94  0  6  0
3 21 12031552 295644      8 136536 1188    0 11348     0 1362 3913  0  1 10 89  0
0 11 12030528 394072      8 151000 2016    0 17304     0  907 2867  0  1 13 86  0
0 11 12030016 485252      8 158528  708    0  7472     0  566 1680  0  1 23 77  0
0 11 12029248 605820      8 159608  900    0  2024     0  371 1289  0  0 31 69  0
0 11 12028992 725344      8 160472 1076    0  1204     0  387 1381  0  1 33 66  0
0 12 12028480 842276      8 162056  724    0  3112     0  357 1142  0  1 38 61  0
0 13 12027968 937828      8 162652  776    0  1312     0  363 1191  0  1 31 68  0
0  9 12027456 1085672      8 163260  656    0  1520     0  439 1497  0  0 30 69  0
0 10 12027200 1207624      8 163684  728    0   992     0  411 1268  0  0 42 58  0
0  9 12026688 1331492      8 164740  600    0  1732     0  392 1203  0  0 36 64  0
0  9 12026432 1458312      8 166020  628    0  1644     0  366 1176  0  0 33 66  0

Come puoi vedere, non appena lo swap viene coinvolto c'è un enorme scambio di 15916880 Kbyte in una sola volta che, immagino, dura per l'intera durata del blocco del sistema. E tutto ciò è apparentemente causato da un processo (il rallentatore) che richiede solo 10 MB al secondo.

AGGIORNAMENTO 2: Ho fatto una rapida installazione di FreeBSD e ripetuto lo stesso schema di allocazione usato con Linux ... ed è stato fluido come dovrebbe essere. FreeBSD ha scambiato le pagine gradualmente mentre il sloweater ha allocato tutti i suoi blocchi di memoria da 10 MB. Neanche un intoppo di alcun tipo ... WTF sta succedendo qui ?!

AGGIORNAMENTO 3: Ho archiviato un bug con il bugtracker del kernel. Sembra che stia ottenendo qualche attenzione, quindi ... incrociamo le dita ...


2
Come ho già detto, tutto è bloccato. Ho provato a lanciarlo da un altro sistema che è scaduto.
John Terragon,

2
Se avvio vmstat 1 con output stdout, penso che si bloccherà. Ma hai ragione, potrei semplicemente iniziare vmstat 1>somefiledirettamente dal sistema e quindi vedere cosa riporta dopo che il sistema è tornato in vita. Ci proverò.
John Terragon,

2
Ho usato vmstat. Risultati nell'aggiornamento sopra.
John Terragon,

3
swappinessè il valore predefinito 60 (non che cambiarlo dia un risultato migliore). Il kernel usato con la vmstatcorsa è 4.14.35 ma ho provato 4.15, 4.16 e sono persino tornato alla serie 4.0 (!): Sempre lo stesso comportamento. E non sto usando una strana distribuzione, è solo debian. Non uso le immagini del kernel di debian (non che le mie abbiano configurazioni insolite) ma ho provato uno di questi ... stesso comportamento.
John Terragon,

2
Discussione molto interessante sul bug del kernel! E sembra che tu abbia isolato questo problema per scambiare la partizione crittografata con LUKS. Potresti voler modificare la tua risposta o eventualmente pubblicare una risposta da solo (con le soluzioni alternative conosciute finora, e forse continuare ad aggiornarla man mano che la discussione su LKML arriva a risultati più conclusivi.) Davvero impressionante vedere la comunità del kernel Linux al lavoro! 😁
filbranden,

Risposte:


1

Questo è esattamente ciò per cui esiste la protezione da thrash .

Monitora costantemente lo stato di scambio e, quando qualcosa inizia a occupare molta RAM, blocca temporaneamente i processi avidi di RAM, quindi il kernel ha il tempo di scambiare un po 'di memoria senza rendere l'intero sistema non rispondente.


-3

Stai solo allocando memoria - in realtà non ci metti nulla. Un programma "normale" alloca un pezzo e poi inizia a usarlo. L'allocazione non è la stessa dell'utilizzo della memoria.


3
Benvenuti a pubblicare su Unix StackExchange. Inserisce i dati al suo interno, che risulta essere pari a zero. Vedi il memset (). Il kernel Linux fornisce una pagina fisica di RAM non appena si scrive sulla pagina virtuale; non esamina il valore specifico che è scritto.
sourcejedi,

In realtà, ho compilato ed eseguito questo sul mio desktop a partire da 2 GB usati, 6 GB gratuiti. In realtà è stato scambiato inizialmente a una velocità lenta e solo quando ha raggiunto il limite è stato scambiato in modo aggressivo, il che ha causato la presa di varie azioni della GUI.
Jeremy Boden,
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.