Ciao, abbiamo trovato la soluzione alla tua domanda, continua a leggere e la troverai poco più in basso.
Soluzione:
Linux non esegue lo "swapping opportunistico" come definito in questa domanda.
I seguenti riferimenti primari non menzionano affatto il concetto:
- Capire il gestore della memoria virtuale di Linux. Un libro online di Mel Gorman. Scritto nel 2003, poco prima del rilascio di Linux 2.6.0.
- Documentation/admin-guide/sysctl/vm.rst. È la documentazione principale delle impostazioni regolabili della gestione della memoria virtuale di Linux.
Più precisamente:
10.6 Demone Pageout (kswapd)
Storicamente
kswapd
si svegliava ogni 10 secondi, ma ora viene svegliato dall'allocatore di pagine fisiche solo quando viene raggiunto il numero pages_low di pagine libere in una zona. [...] In condizioni di estrema pressione sulla memoria, i processi svolgeranno il lavoro dikswapd
in modo sincrono. [...]kswapd
continua a liberare pagine finché non viene raggiunta la soglia pages_high.
In base a quanto detto sopra, non ci si aspetta alcuno swapping quando il numero di pagine libere è superiore alla "filigrana alta".
In secondo luogo, questo ci dice lo scopo di kswapd
è quello di creare più pagine libere.
Quando kswapd
scrive una pagina di memoria in swap, libera immediatamente la pagina di memoria. kswapd non mantiene in memoria una copia della pagina swappata..
Linux 2.6 usa "rmap" per liberare la pagina. In Linux 2.4, la storia era più complessa. Quando una pagina era condivisa da più processi, kswapd non era in grado di liberarla immediatamente. Questa è storia antica. Tutti i post collegati riguardano Linux 2.6 o superiore.
swappiness
Questo controllo è usato per definire quanto aggressivo il kernel scambierà le pagine di memoria.
pagine di memoria. Valori più alti aumentano l'aggressività, mentre valori più bassi
diminuiscono la quantità di swap. Un valore di 0 indica al kernel di non avviare lo swap
di swap fino a quando la quantità di memoria libera e di pagine supportate da file è inferiore
meno del limite massimo in una zona.
Questa citazione descrive un caso speciale: se si configura il parametro swappiness
per essere 0
. In questo caso, inoltre, non ci si dovrebbe aspettare alcuno swapping fino a quando il numero di pagine di cache non sarà sceso alla soglia massima. In altre parole, il kernel cercherà di scartare quasi tutta la cache dei file prima di iniziare lo swapping. (Questo potrebbe causare forti rallentamenti. È necessario avere un po' di file cache! La cache dei file viene utilizzata per contenere il codice di tutti i programmi in esecuzione 🙂
Cosa sono le filigrane?
Le citazioni di cui sopra sollevano la domanda: Quanto sono grandi le riserve di memoria "filigrana" sul mio sistema? Risposta: su un sistema "piccolo", le filigrane di zona predefinite possono raggiungere il 3% della memoria. Ciò è dovuto al calcolo della filigrana "minima". Sui sistemi più grandi le filigrane saranno una percentuale minore, vicina allo 0,3% della memoria.
Quindi, se la domanda riguarda un sistema con più del 10% di memoria libera, i dettagli esatti di questa logica di watermark non sono significativi.
I watermark per ogni singola "zona" sono mostrati in /proc/zoneinfo
come documentato in proc(5). Un estratto dal mio zoneinfo:
Node 0, zone DMA32
pages free 304988
min 7250
low 9062
high 10874
spanned 1044480
present 888973
managed 872457
protection: (0, 0, 4424, 4424, 4424)
...
Node 0, zone Normal
pages free 11977
min 9611
low 12013
high 14415
spanned 1173504
present 1173504
managed 1134236
protection: (0, 0, 0, 0, 0)
Le "filigrane" attuali sono min
, low
e high
. Se un programma richiede una quantità di memoria tale da ridurre il valore di free
sotto min
il programma entra in "recupero diretto". Il programma deve attendere mentre il kernel libera la memoria.
Se possibile, vogliamo evitare il recupero diretto. Quindi se free
scendesse al di sotto del valore low
il kernel risveglia kswapd
. kswapd
libera la memoria con lo swapping e/o eliminando le cache, fino a quando free
è superiore a high
di nuovo.
Qualifica aggiuntiva: kswapd
viene eseguito anche per proteggere l'intera quantità di lowmem_reserve, per l'uso di lowmem e DMA del kernel. La lowmem_reserve predefinita è circa 1/256 dei primi 4GiB di RAM (zona DMA32), quindi di solito è di circa 16MiB.
Impegni per il codice di Linux
mm: scala i watermark di kswapd in proporzione alla memoria
[...]
fattore_scala_filigrana:
Questo fattore controlla l'aggressività di kswapd. Definisce la
quantità di memoria lasciata in un nodo/sistema prima che kswapd venga svegliato e
quanta memoria deve essere liberata prima che kswapd torni a dormire.L'unità di misura è in frazioni di 10.000. Il valore predefinito di 10 significa che le
tra le filigrane è pari allo 0,1% della memoria disponibile nel nodo/sistema.
nodo/sistema. Il valore massimo è 1000, ovvero il 10% della memoria.Un'alta frequenza di thread che entrano in direct reclaim (allocstall) o kswapd
di andare a dormire prematuramente (kswapd_low_wmark_hit_quickly) può indicare che il numero di pagine libere di kswapd
che il numero di pagine libere che kswapd mantiene per ragioni di latenza è
troppo piccolo per i burst di allocazione che si verificano nel sistema. Questa manopola
può essere usata per regolare di conseguenza l'aggressività di kswapd.
proc: meminfo: stima più prudente della memoria disponibile
Il
MemAvailable
in/proc/meminfo
è quello di dare agli utenti un'indicazione di quanta
di quanta memoria è allocabile senza causare lo swapping, quindi esclude
le filigrane basse delle zone come non disponibili per lo spazio utente.Tuttavia, per un'allocazione nello spazio utente,
kswapd
reclamerà effettivamente
fino a quando le pagine libere non raggiungono una combinazione tra l'high watermark e la protezione lowmem del
protezione lowmem dell'allocatore di pagine che mantiene una certa quantità di memoria DMA
e DMA32 dallo spazio utente.Sottraete dal numero di pagine libere l'intera quantità che sappiamo non essere disponibile per lo spazio utente.
dal numero di pagine libere quando si calcola MemAvailable.
Codice Linux
A volte si sostiene che cambiare swappiness
a 0
disabiliterà di fatto lo "swapping opportunistico". Questo fornisce un interessante spunto di indagine. Se esiste qualcosa chiamato "swapping opportunistico", e può essere regolato dalla swappiness, allora si potrebbe cercare di individuare tutte le catene di chiamate che leggono vm_swappiness
. Si noti che possiamo ridurre lo spazio di ricerca assumendo che CONFIG_MEMCG
non sia impostato (cioè i "gruppi di memoria" siano disabilitati). La catena di chiamate va:
- vm_swappiness
- mem_cgroup_swappiness
- numero_di_scarichi
- restringere_nodo_memcg
- restringere_nodo
shrink_node_memcg
è commentato "Si tratta di un liberatore di pagine di base per nodo. Utilizzato sia da kswapd che da direct reclaim". Vale a dire che questa funzione aumenta il numero di pagine di libero pagine libere. Non sta cercando di duplicare le pagine da scambiare in modo che possano essere liberate in un momento successivo. Ma anche se non teniamo conto di questo:
La catena di cui sopra viene chiamata da tre funzioni diverse, mostrate di seguito. Come ci si aspettava, possiamo dividere le chiamate in reclaim diretto e kswapd. Non avrebbe senso eseguire uno "swapping opportunistico" in direct reclaim.
-
/* * This is the direct reclaim path, for page-allocating processes. We only * try to reclaim pages from zones which will satisfy the caller's allocation * request. * * If a zone is deemed to be full of pinned pages then just give it a light * scan then give up on it. */ static void shrink_zones
-
* kswapd shrinks a node of pages that are at or below the highest usable * zone that is currently unbalanced. * * Returns true if kswapd scanned at least the requested number of pages to * reclaim or if the lack of progress was due to pages under writeback. * This is used to determine if the scanning priority needs to be raised. */ static bool kswapd_shrink_node
-
* For kswapd, balance_pgdat() will reclaim pages across a node from zones * that are eligible for use by the caller until at least one zone is * balanced. * * Returns the order kswapd finished reclaiming at. * * kswapd scans the zones in the highmem->normal->dma direction. It skips * zones which have free_pages > high_wmark_pages(zone), but once a zone is * found to have free_pages <= high_wmark_pages(zone), any page in that zone * or lower is eligible for reclaim until at least one usable zone is * balanced. */ static int balance_pgdat
Quindi, presumibilmente la richiesta è che kswapd venga svegliato in qualche modo, anche quando tutte le allocazioni di memoria vengono soddisfatte immediatamente dalla memoria libera. Ho esaminato gli usi di wake_up_interruptible(&pgdat->kswapd_wait)
e non vedo alcun risveglio di questo tipo.
No, non esiste lo swapping opportunistico in Linux. Ho passato un po' di tempo a esaminare il problema e tutte le fonti (libri di testo, e-mail sulle liste di posta degli sviluppatori del kernel, codice sorgente di Linux e commenti sui commit, e alcuni scambi su Twitter con Mel Gorman) mi dicono la stessa cosa: Linux recupera la memoria solo in risposta a qualche forma di pressione sulla memoria (con l'ovvia eccezione dell'ibernazione).
Tutte le idee sbagliate diffuse sull'argomento probabilmente derivano dal semplice fatto che Linux non può permettersi di aspettare l'ultimo byte di memoria libera prima di iniziare lo swapping. Ha bisogno di una sorta di cuscinetto per proteggersi da forme estreme di esaurimento della memoria, e ci sono alcune regolazioni che possono influenzare la dimensione di tale cuscinetto (ad esempio, la funzione " vm.min_free_kbytes
" di Linux non è un problema.vm.min_free_kbytes
). Ma non è la stessa cosa di "swappare perché non c'è niente di meglio da fare".
Sfortunatamente l'algoritmo di recupero delle pagine è diventato molto più complesso rispetto alla versione 2.6 (quando era descritto in dettaglio nel libro di Mel Gorman), ma l'idea di base è più o meno la stessa: il recupero delle pagine è innescato da allocazioni fallite, che poi o risvegliano kswapd
o cercano di liberare le pagine in modo sincrono (a seconda della pressione della memoria, dei flag di allocazione e di altri fattori).
La ragione più ovvia per cui le allocazioni di pagine possono iniziare a fallire quando rimane abbastanza memoria libera è che potrebbero richiedere memoria contigua mentre in realtà la memoria potrebbe essere troppo frammentata per soddisfare la richiesta. Storicamente, gli sviluppatori del kernel Linux hanno fatto di tutto per evitare la necessità di allocazioni contigue. Ciononostante, alcuni driver di periferica lo richiedono ancora, sia perché non possono eseguire I/O di memoria multipagina (DMA scatter-gather), sia perché potrebbe trattarsi di una codifica approssimativa da parte degli sviluppatori del driver. L'avvento delle Transparent Huge Pages (THP) ha fornito un'altra ragione per allocare la memoria in pezzi fisicamente contigui.
La compattazione a zone, introdotta nello stesso periodo, dovrebbe aiutare a risolvere il problema della frammentazione della memoria, ma non sempre produce l'effetto sperato.
Esistono vari vmscan
che possono aiutare a capire cosa sta succedendo esattamente nel vostro caso specifico -- è sempre più facile trovare le cose necessarie nel codice del kernel Linux quando si hanno stack di chiamate specifici, piuttosto che scansionare tutto ciò che sembra lontanamente rilevante.
Se ti piace l'idea, hai il potere di lasciare un articolo su cosa aggiungeresti a questa cronaca.