2010-09-24 6 views
5

Ho un problema che è stato descritto in più thread riguardanti la mappatura della memoria e un crescente consumo di memoria sotto Linux.I file mappati di memoria Linux riservano molta memoria fisica

Quando apro un file da 1 GB sotto Linux o MacOS X e la mappa in memoria usando

me.data_begin = mmap(NULL, capacity(me), prot, MAP_SHARED, me.file.handle, 0); 

e sequenzialmente leggere la memoria mappata, il mio programma utilizza la memoria più fisica, anche se ho usato posix_madvise (anche chiamato più volte durante il processo di lettura):

posix_madvise(me.data_begin, capacity(me), MMAP_SEQUENTIAL); 

senza successo. :-(

ho provato:

  • diverse bandiere MMAP_RANDOM, MMAP_DONTNEED, MMAP_NORMAL senza successo
  • posix_fadvise (me.file.handle, 0, capacità (ME), POSIX_FADV_DONTNEED) prima e dopo la chiamata mmap -> nessun successo

E funziona con Mac OS X !!! quando combino

posix_madvise(.. MMAP_SEQUENTIAL) 

e

msync(me.data_begin, capacity(me), MS_INVALIDATE). 

La memoria residente è inferiore a 16M (I periodicamente chiamato msync dopo 16mio gradini).

Ma sotto Linux niente funziona. Qualcuno ha un'idea o una storia di successo per il mio problema sotto Linux?

Cheers, David

+0

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

+0

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

+0

@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). –

risposta

8

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.

+0

Grazie, Juliano, il comportamento del 50% è interessante. Mi chiedo semplicemente perché non c'è modo di imporre Linux per liberare pagine che non ho mai più letto. Invece sacrifica i buffer e le cache del file system. Su MacOS X il sacrificio di questi buffer blocca il sistema fino a quando non è completamente inutilizzabile. Ma fortunatamente possiamo impedirlo tramite * msync (... MS_INVALIDATE) * Su Linux sembra essere il comportamento osservato con madvice che impedisce il blocco del sistema. – Dave

+1

@Dave: considera che non vi è alcun motivo per liberare prematuramente quelle pagine. Linux non sta sacrificando cache e buffer, ma sta facendo esattamente questo. Mentre leggi più dati dal disco, Linux deve comunque portarli alla memoria. È una sorta di cache di ciò che è stato letto dal disco, ma invece di renderlo conto come "cache", lo considera come parte della parte di RSS del processo che ha mappato quel file. Quando Linux ha bisogno di nuovo cache, libererà quelle pagine mappate a quell'applicazione. Non devi preoccuparti di questo! – Juliano

+0

@Juliano: considera che MADV_SEQUENTIAL indica in modo specifico al sistema che le pagine saranno accessibili tramite una lettura sequenziale una sola volta. Queste pagine sono candidati perfetti per il recupero.Invece, vedo che sulla mia scatola, fino al raggiungimento del 50% della memoria (32 GB in quel caso), la cache dei file viene recuperata. E vedo che l'esecuzione di altri processi è degradante, Ora ho trovato un modo ridicolo di forzare Linux a non farlo. Disimballando e mappando nuovamente il file, ogni 1 GB circa. Quello * DOES * risolve il problema e dopo non vedo degrado performace per altri processi. –