gestione della memoria di Linux è diverso da altri sistemi. Il principio chiave è che la memoria che non viene utilizzata è sprecata memoria. In molti modi, Linux cerca di massimizzare l'utilizzo della memoria, risultante (il più delle volte) in prestazioni migliori.
Non è che "nulla funzioni" in Linux, ma che il suo comportamento è leggermente diverso da quello che ci si aspetta.
Quando le pagine di memoria vengono estratte dal file mmapp, il sistema operativo deve decidere quali pagine di memoria fisica verranno rilasciate (o scambiate) per poter essere utilizzate. Cerca le pagine che sono più facili da sostituire (non richiedono la scrittura immediata del disco) e hanno meno probabilità di essere riutilizzate.
La chiamata POSIX di madvice() serve a comunicare al sistema in che modo l'applicazione utilizzerà le pagine. Ma come dice il nome, è un avviso in modo che il sistema operativo sia meglio strumentato nel prendere le decisioni di paging e swap. Non è né una politica né un ordine.
Per dimostrare gli effetti di madvice() su Linux, ho modificato uno degli esercizi che do ai miei studenti. Vedi lo complete source code here. Il mio sistema è a 64 bit e ha 2 GB di RAM, che attualmente è in uso per circa il 50%. Usando il programma per mmap un file da 2 GB, leggerlo in modo sequenziale e scartare tutto. Segnala l'utilizzo di RSS ogni 200 MB viene letto.I risultati senza madvice():
<[email protected]> ~% ./madvtest file.dat n
0 : 3 MB
200 : 202 MB
400 : 402 MB
600 : 602 MB
800 : 802 MB
1000 : 1002 MB
1200 : 1066 MB
1400 : 1068 MB
1600 : 1078 MB
1800 : 1113 MB
2000 : 1113 MB
Linux continuato a spingere le cose fuori di memoria fino a circa 1 GB è stato letto. Successivamente, ha iniziato a pressare il processo stesso (poiché l'altro 50% della memoria era attivo dagli altri processi) e si è stabilizzato fino alla fine del file.
Ora, con madvice():
<[email protected]> ~% ./madvtest file.dat y
0 : 3 MB
200 : 202 MB
400 : 402 MB
600 : 494 MB
800 : 501 MB
1000 : 518 MB
1200 : 530 MB
1400 : 530 MB
1600 : 530 MB
1800 : 595 MB
2000 : 788 MB
Nota che Linux ha deciso di assegnare pagine al processo unico fino a raggiungere circa 500 MB, molto prima di quanto senza madvice(). Questo perché dopo, le pagine attualmente in memoria sembravano molto più preziose delle pagine che erano contrassegnate come accesso sequenziale da questo processo. C'è una soglia in VMM che definisce quando iniziare a rilasciare vecchie pagine dal processo.
Si potrebbe chiedere perché Linux ha continuato a allocare pagine fino a circa 500 MB e non si è interrotto molto prima, poiché sono stati contrassegnati come accesso sequenziale. È che il sistema aveva comunque abbastanza pagine di memoria libere, o le altre pagine residenti erano troppo vecchie per essere conservate. Tra tenere in memoria le pagine antiche che non sembrano più utili e portare più pagine a servire un programma che è in esecuzione ora, Linux sceglie la seconda opzione.
Anche se erano contrassegnati come accesso sequenziale, era solo un consiglio. L'applicazione potrebbe comunque voler tornare a quelle pagine e leggerle di nuovo. O un'altra applicazione nel sistema. La chiamata a madvice() dice solo ciò che l'applicazione stessa sta facendo, Linux prende in considerazione l'immagine più grande.
Può essere o non essere rilevante, ma dovrebbe essere utile sapere: stai usando un sistema a 32 o 64 bit? Sei consapevole che non dovresti mmapare 1GB in un sistema a 32 bit? (anche se si utilizza un sistema a 64 bit, si potrebbe essere preoccupati per la portabilità). – Juliano
Tutti i sistemi sono a 64 bit (con puntatori e offset di file a 64 bit) e posso mappare correttamente file da 40 GB. Ho semplicemente ridotto il problema a 1 GB per motivi di riproducibilità. – Dave
@Sven. Ci sono casi in cui l'uso di una mappatura della memoria è inevitabile, ad esempio quando una chiamata alla libreria richiede un'area di memoria, piuttosto che un file. Quindi il tuo suggerimento è inutile e non risponde alla domanda. Per quanto riguarda la risposta, apparentemente su Linux MMAP_SEQUENTIAL è praticamente * rotto *. La parte read-ahead funziona, la parte reclaiming della pagina no. E l'unico modo suggerisce a Linux che in realtà queste pagine siano dei buoni candidati è annullando la mappatura della regione (e mappandola di nuovo). –