Linux non esegue lo "scambio 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.
- Documentazione/admin-guide/sysctl/vm.rst. Questa è la documentazione principale delle impostazioni sintonizzabili della gestione della memoria virtuale di Linux.
Più specificamente:
10.6 Demone Pageout (kswapd)
Storicamente
kswapd
prima si svegliava ogni 10 secondi, ma ora viene svegliato solo dall'allocatore di pagine fisiche quando viene raggiunto il numero di pagine libere in una zona. [...] Sotto estrema pressione della memoria, i processi faranno il lavoro dikswapd
in modo sincrono. [...]kswapd
continua a liberare le pagine finché non viene raggiunto il limite massimo di pagine.
Sulla base di quanto sopra, non ci aspetteremmo alcuno scambio quando il numero di pagine libere è superiore al "high watermark".
In secondo luogo, questo ci dice lo scopo di kswapd
è creare più pagine libere.
Quando kswapd
scrive una pagina di memoria da scambiare, libera immediatamente la pagina di memoria. kswapd non conserva in memoria una copia della pagina scambiata .
Linux 2.6 utilizza "rmap" per liberare la pagina. In Linux 2.4, la storia era più complessa. Quando una pagina veniva 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 aggressivamente il kernel scambierà le pagine di memoria. Valori più alti aumenteranno l'aggressività, valori più bassi diminuiranno la quantità di scambio. Un valore pari a 0 indica al kernel di non avviare lo scambio fino alla quantità di pagine libere e supportate da file è inferiore all'high water mark in una zona.
Questa citazione descrive un caso speciale:se configuri il swappiness
il valore deve essere 0
. In questo caso, inoltre, non dovremmo aspettarci alcuno scambio fino a quando il numero di pagine della cache non sarà sceso al limite massimo. In altre parole, il kernel proverà a scartare quasi tutta la cache dei file prima di iniziare lo scambio. (Ciò potrebbe causare enormi rallentamenti. È necessario disporre di un po' di cache dei file! La cache dei file viene utilizzata per contenere il codice di tutti i programmi in esecuzione :-)
Cosa sono le filigrane?
Le citazioni sopra sollevano la domanda:quanto sono grandi le riserve di memoria "watermark" sul mio sistema? Risposta:su un sistema "piccolo", le filigrane di zona predefinite potrebbero raggiungere il 3% della memoria. Ciò è dovuto al calcolo della filigrana "min". Sui sistemi più grandi le filigrane saranno una proporzione minore, che si avvicina 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 della filigrana non sono significativi.
Le filigrane per ogni singola "zona" sono mostrate 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 attuali "filigrane" sono min
, low
e high
. Se un programma richiede memoria sufficiente per ridurre free
sotto min
, il programma entra in "recupero diretto". Il programma viene fatto attendere mentre il kernel libera memoria.
Vogliamo evitare il recupero diretto, se possibile. Quindi se free
scenderebbe sotto low
watermark, il kernel riattiva kswapd
. kswapd
libera memoria scambiando e/o eliminando le cache, fino a free
è superiore a high
di nuovo.
Qualifica aggiuntiva:kswapd
funzionerà anche per proteggere l'intera quantità lowmem_reserve, per l'utilizzo del kernel lowmem e DMA. Il lowmem_reserve predefinito è circa 1/256 dei primi 4GiB di RAM (zona DMA32), quindi di solito è di circa 16MiB.
Commit del codice Linux
mm:scala le filigrane kswapd in proporzione alla memoria
[...]
watermark_scale_factor:
Questo fattore controlla l'aggressività di kswapd. Definisce la quantità di memoria rimasta in un nodo/sistema prima che kswapd venga riattivato e quanta memoria deve essere libera prima che kswapd torni a dormire.
L'unità è in frazioni di 10.000. Il valore predefinito di 10 indica che le distanze tra le filigrane sono pari allo 0,1% della memoria disponibile nel nodo/sistema. Il valore massimo è 1000, o il 10% della memoria.
Un'alta percentuale di thread che entrano nel recupero diretto (allocstall) o che kswapd va in sospensione prematuramente (kswapd_low_wmark_hit_quickly) può indicare che il numero di pagine libere che kswapd mantiene per motivi di latenza è troppo piccolo per i picchi di allocazione che si verificano nel sistema. Questa manopola può quindi essere utilizzata per regolare l'aggressività di kswapd di conseguenza.
proc:meminfo:stima la memoria disponibile in modo più conservativo
Il
MemAvailable
elemento in/proc/meminfo
è quello di dare agli utenti un suggerimento di quanta memoria è allocabile senza causare lo scambio, quindi esclude i limiti minimi delle zone come non disponibili per lo spazio utente.Tuttavia, per un'allocazione dello spazio utente,
kswapd
verrà effettivamente recuperato fino a quando le pagine libere non raggiungono una combinazione di high watermark e protezione lowmem dell'allocatore di pagine che mantiene anche una certa quantità di memoria DMA e DMA32 dallo spazio utente.Sottrai l'intero importo che sappiamo essere non disponibile per lo spazio utente dal numero di pagine libere durante il calcolo di MemAvailable.
Codice Linux
A volte si afferma che la modifica di swappiness
a 0
disabiliterà efficacemente lo "scambio opportunistico". Ciò fornisce un'interessante via di indagine. Se c'è qualcosa chiamato "scambio opportunistico", e può essere regolato da swappiness, allora potremmo inseguirlo trovando tutte le catene di chiamate che leggono vm_swappiness
. Nota che possiamo ridurre il nostro spazio di ricerca assumendo CONFIG_MEMCG
non è impostato (cioè i "memory cgroups" sono disabilitati). La catena di chiamate va:
- vm_swappiness
- mem_cgroup_swappiness
- get_scan_count
- shrink_node_memcg
- shrink_node
shrink_node_memcg
è commentato "Questa è una pagina base per nodo più libera. Usata sia da kswapd che da direct reclaim". Cioè. questa funzione aumenta il numero di free pagine. Non sta tentando di duplicare le pagine da scambiare in modo che possano essere liberate in un secondo momento. Ma anche se lo escludiamo:
La catena sopra è chiamata da tre diverse funzioni, mostrate di seguito. Come previsto, possiamo dividere i siti di chiamata in bonifica diretta vs. kswapd. Non avrebbe senso eseguire "scambi opportunistici" nel recupero diretto.
/* * 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 l'affermazione è che kswapd viene 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 risvegli come questo.
No, non esiste lo scambio 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 rivendica solo memoria in risposta a qualche forma di pressione della memoria (con l'ovvia eccezione dell'ibernazione).
Tutti i malintesi popolari sull'argomento probabilmente derivano dal semplice fatto che Linux non può permettersi di aspettare fino all'ultimo byte di memoria libera prima di iniziare lo scambio. Ha bisogno di una sorta di cuscino per proteggerlo da forme estreme di esaurimento della memoria, e ci sono alcuni sintonizzabili che possono influenzare la dimensione di quel cuscino (ad es. vm.min_free_kbytes
). Ma non è la stessa cosa di "scambiare perché non c'è niente di meglio da fare".
Sfortunatamente l'algoritmo di page frame reclamation è diventato molto più complesso rispetto a 2.6 (quando era descritto in dettaglio nel libro di Mel Gorman), ma l'idea di base è più o meno la stessa:page reclamation è innescata da allocazioni fallite, che poi o sveglia kswapd
oppure prova a 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 pagina potrebbero iniziare a fallire con sufficiente memoria libera rimanente è 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. Tuttavia, alcuni driver di dispositivo lo richiedono ancora, o perché non possono eseguire I/O di memoria multipagina (DMA scatter-gather), o potrebbe essere solo una codifica sciatta da parte degli sviluppatori di driver. L'avvento di Transparent Huge Pages (THP) ha fornito un altro motivo per allocare la memoria in blocchi fisicamente contigui.
La compattazione delle zone, che è stata introdotta più o meno nello stesso periodo di tempo, dovrebbe aiutare con il problema della frammentazione della memoria, ma non sempre produce l'effetto previsto.
Ci sono vari vmscan
punti di traccia che possono aiutare a capire cosa sta succedendo esattamente nel tuo caso specifico:è sempre più facile trovare le cose che ti servono nel codice del kernel Linux quando hai stack di chiamate specifici, piuttosto che scansionare tutto ciò che sembra remotamente rilevante.