2012-04-24 26 views
12

Sto scrivendo un programma che riceve enormi quantità di dati (in pezzi di dimensioni diverse) dalla rete, li elabora e li scrive in memoria. Poiché alcuni dati possono essere molto grandi, il mio approccio attuale sta limitando la dimensione del buffer utilizzata. Se un pezzo è più grande della dimensione massima del buffer, scrivo i dati in un file temporaneo e in seguito leggo il file in blocchi per l'elaborazione e l'archiviazione permanente.mmap e utilizzo memoria

Mi chiedo se questo può essere migliorato. Ho letto di mmap per un po ', ma non sono sicuro al cento per cento se può aiutarmi. La mia idea è di usare mmap per leggere il file temporaneo. Questo aiuta in qualche modo? La cosa principale che mi preoccupa è che un grande file occasionale non dovrebbe riempire la mia memoria principale causando il resto di tutto il resto.

Inoltre, pensi che l'approccio con i file temporanei sia utile? Dovrei farlo anche io o, forse, dovrei fidarmi del gestore della memoria linux per fare il lavoro per me? O dovrei fare qualcos'altro?

+0

Quanto è grande "grande"? Ancora più importante, come si confronta con la RAM reale totale sul computer in cui verrà eseguito? – zwol

+0

Big è di diversi gigabyte. Ho 24G di RAM, quindi alcuni file possono occupare fino a un quarto della RAM fisica o anche di più. – Elektito

+1

Fondamentalmente, usando 'mmap()', stai facendo in modo che quella memoria sia supportata da un file, invece di essere supportata da swap (la cosiddetta memoria anonima). Sotto la pressione della memoria, il kernel può decidere di recuperare la memoria con supporto dei file in modo più aggressivo rispetto alla memoria anonima, o potrebbe fare il contrario, non lo so. – ninjalj

risposta

10

mmap può aiutare in qualche modo, mi spiego con alcuni esempi ipotetici:

Prima cosa: Diciamo che si sta esaurendo la memoria, e l'applicazione che hanno un pezzo 100MB di malloc'ed la memoria ottiene il 50% di esso scambiato, il che significa che il sistema operativo ha dovuto scrivere 50 MB nel file di scambio e, se hai bisogno di leggerlo, lo hai scritto, occupato e poi riletto 50 MB del tuo file di scambio.

Nel caso in cui la memoria sia stata appena memorizzata, il sistema operativo non scriverà quella parte di informazione nel file di scambio (poiché sa che i dati sono identici al file stesso), invece, farà solo un graffio di 50MB di informazioni (di nuovo: supponendo che tu non abbia scritto nulla per ora) e questo è quanto. Se hai sempre bisogno che la memoria venga nuovamente letta, il sistema operativo recupererà il contenuto non dallo swapfile, ma dal file originale che hai salvato, quindi se qualsiasi altro programma ha bisogno di 50 MB di swap, sono disponibili. Inoltre non c'è nulla di sovraccarico con la manipolazione di swapfile.

Diciamo che si legge un chunk di dati di 100 MB, e in base al 1 MB iniziale di dati di intestazione, l'informazione che si desidera si trova in offset 75 MB, quindi non è necessario nulla tra 1 ~ 74.9 MB! Hai letto per niente ma per semplificare il tuo codice. Con mmap, si leggeranno solo i dati effettivamente utilizzati (arrotondato a 4kb, o la dimensione della pagina del sistema operativo, che è in genere 4kb), quindi leggerà solo il primo e il 75esimo MB. Penso che sia molto difficile creare un modo più semplice ed efficace per evitare la lettura del disco rispetto ai file mmaping. E se per qualche motivo hai bisogno dei dati con l'offset 37 MB, puoi semplicemente usarlo! Non è necessario decomprimerlo nuovamente, poiché l'intero file è accessibile in memoria (ovviamente limitato dallo spazio di memoria del processo).

Tutti i file mmap'ed vengono sottoposti a backup da soli, non dal file di scambio, lo swapfile viene creato per concedere dati che non hanno un file di cui eseguire il backup, che di solito è data malloc'ed o dati supportati su un file, ma è stato modificato e [non può/non deve] essere riscritto ad esso prima che il programma comunichi effettivamente al sistema operativo di farlo tramite una chiamata msync.

Attenzione che non è necessario mappare l'intero file nella memoria, è possibile mappare qualsiasi quantità (il secondo arg è "size_t length") a partire da qualsiasi posizione (sesto arg - "off_t offset"), ma a meno che il tuo file è probabilmente enorme, puoi tranquillamente mappare 1 GB di dati senza paura, anche se il sistema contiene solo 64 MB di memoria fisica, ma questo è per la lettura, se hai intenzione di scrivere dovresti essere più prudente e mappare solo il cose di cui hai bisogno.

La mappatura dei file ti aiuterà a semplificare il codice (hai già il contenuto del file in memoria, pronto per l'uso, con un sovraccarico di memoria molto minore dato che non è memoria anonima) e più veloce (leggerai solo i dati che accesso al programma).

+0

Grazie. È bello sapere tutto questo, anche se sfortunatamente la maggior parte di questo non si applica alla mia situazione attuale. – Elektito

3

Il vantaggio principale di mmap con file di grandi dimensioni è quello di condividere la stessa mappatura di memoria tra due o più file: se si usa mmap con MAP_SHARED, verrà caricato in memoria una sola volta per tutti i processi che utilizzeranno i dati con il risparmio di memoria.

Ma AFAIK, mmap mappa l'intero file in memoria (Here è possibile trovare esempi di come mmap non riesce con i file più grandi di spazio mem + swap fisico.) Quindi se si accede al file da un singolo processo, non sarà di aiuto tu con il consumo di memoria fisica.

+0

Quindi c'è un altro modo in cui posso essere sicuro che non tutto il file sia caricato in memoria? Vedi, anch'io ho un altro problema. Devo inviare i dati per l'archiviazione in MongoDB. Ora Mongo ha bisogno di me per dargli un puntatore ad un buffer in memoria e quindi sembra che, caricando il file da solo o usando mmap, il file verrà memorizzato nella sua interezza per un periodo di tempo. – Elektito

+2

Non ho familiarità con MongoDB, ma se vuole un buffer in memoria contenente l'intero file, allora mi sembra che non abbia senso usare i file temporanei. Se il comportamento durante la lettura diretta dalla rete nei buffer di memoria e poi il passaggio a MongoDB è inaccettabile, penso che dovrai rompere i tuoi file di grandi dimensioni in blocchi * all'interno del database *. – zwol

+0

mmap infatti "mappa l'intero file in memoria", ma non * lo legge dal disco in memoria * per farlo. Mappare file più grandi dello spazio fisico mem + swap potrebbe fallire solo se si usano flag specificati o in configurazioni kernel specifiche (che non sono comunemente usate) o se si tenta di mmap i file con dimensioni totali maggiori della memoria * virtuale *. L'esaurimento della memoria virtuale è la vera minaccia sui sistemi a 32 bit, ma qualsiasi altra cosa non dovrebbe causare il fallimento di mmap quando lo si fa nel modo giusto. – user1643723

1

Credo che mmap non richieda che tutti i dati siano in memoria nello stesso momento - utilizza la cache della pagina per mantenere in memoria le pagine utilizzate di recente e il resto su disco.

Se stai leggendo un blocco alla volta, l'utilizzo di un file temporaneo probabilmente non ti aiuterà, ma se stai leggendo più blocchi contemporaneamente utilizzando più thread, processi o usando select/poll, allora potrebbe.