Domanda

Ho alcuni file di grandi dimensioni ho bisogno di analizzare, e la gente è stato consigliato mmap perché questo dovrebbe evitare di dover destinare l'intero file in memoria.

Ma guardando 'top' lo fa apparire come sto aprendo l'intero file in memoria, quindi penso che devo fare qualcosa di sbagliato. 'Top spettacoli> 2.1 concerto'

Questo è un frammento di codice che mostra quello che sto facendo.

Grazie

#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <fcntl.h>
#include <sysexits.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <cstring>
int main (int argc, char *argv[] ) {
  struct stat sb;
  char *p,*q;
  //open filedescriptor
  int fd = open (argv[1], O_RDONLY);
  //initialize a stat for getting the filesize
  if (fstat (fd, &sb) == -1) {
    perror ("fstat");
    return 1;
  }
  //do the actual mmap, and keep pointer to the first element
  p =(char *) mmap (0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
  q=p;
  //something went wrong
  if (p == MAP_FAILED) {
    perror ("mmap");
    return 1;
  }
  //lets just count the number of lines
  size_t numlines=0;
  while(*p++!='\0')
    if(*p=='\n')
      numlines++;
  fprintf(stderr,"numlines:%lu\n",numlines);
  //unmap it
  if (munmap (q, sb.st_size) == -1) {
    perror ("munmap");
    return 1;
  }
  if (close (fd) == -1) {
    perror ("close");
    return 1;
  }
  return 0;
}
È stato utile?

Soluzione

No, quello che stai facendo è mappatura il file nella memoria. Questo è diverso in realtà la lettura del file in memoria.

Sono stati di leggere dentro, si dovrà trasferire l'intero contenuto nella memoria. Con la mappatura di esso, si lascia gestire il sistema operativo esso. Se si tenta di leggere o scrivere in una posizione in quell'area di memoria, il sistema operativo verrà caricato l'apposita sezione per la prima volta. Sarà non caricare l'intero file a meno che non è necessario l'intero file.

Ecco dove si ottiene il guadagno di prestazioni. Se si mappa l'intero file, ma cambia solo un byte allora unmap esso, troverete che non c'è molto disco I / O a tutti.

Naturalmente, se si tocca ogni byte del file, allora sì, sarà tutto caricato ad un certo punto, ma non necessariamente in RAM fisica tutto in una volta. Ma questo è il caso, anche se si carica l'intero file in attacco. Il sistema operativo sarà scambiare parti dei vostri dati se non c'è abbastanza memoria fisica per contenere il tutto, insieme a quella degli altri processi nel sistema.

I principali vantaggi della mappatura della memoria sono:

  • si rinviare la lettura delle sezioni di file fino a quando non sono necessari (e, se sono mai necessari, non ottengono carico). Quindi non c'è nessun grande costo upfront come si carica l'intero file. Si ammortizza il costo di carico.
  • Le operazioni di scrittura sono automatizzate, non c'è bisogno di scrivere ogni byte. Basta chiuderlo e il sistema operativo scriverà le sezioni modificate. Credo che questo accade anche quando la memoria viene scambiata come pure (in condizioni di scarsa memoria fisica), dal momento che il buffer è semplicemente una finestra sul file.

Tenete a mente che non v'è più probabile uno scollamento tra l'utilizzo dello spazio indirizzo e l'uso della memoria fisica. È possibile assegnare uno spazio di indirizzi di 4G (idealmente, anche se ci possono essere OS, BIOS o limitazioni hardware) in una macchina a 32-bit con solo 1G di RAM. Il sistema operativo gestisce il paging e dal disco.

E per rispondere alla vostra ulteriore richiesta di chiarimento:

  

Giusto per chiarire. Quindi, se ho bisogno di tutto il file, mmap sarà effettivamente caricare l'intero file?

Sì, ma non può essere in fisico di memoria tutto in una volta. Il sistema operativo sarà scambiare i bit di nuovo al file system al fine di portare a nuovi bit.

Ma sarà anche farlo se avete letto l'intero file manualmente. La differenza tra queste due situazioni è la seguente.

Con il file letto nella memoria manualmente, il sistema operativo scambiare parti del tuo spazio di indirizzamento (possono comprendere i dati o non può) fuori per il file di swap. E sarà necessario riscrivere manualmente il file quando il vostro finito con esso.

Con la mappatura della memoria, si hanno effettivamente detto che per utilizzare il file originale come una zona in più di swap per il file / la memoria solo . E, quando i dati vengono scritti che area di swap, colpisce il file effettivo immediatamente. Quindi non dover riscrivere manualmente nulla quando hai finito e non colpisce lo swap normale (di solito).

E 'davvero solo una finestra per il file:

image file di memoria mappata

Altri suggerimenti

È inoltre possibile utilizzare fadvise (2) (e madvise (2), puoi anche consultare posix_fadvise & posix_madvise) per contrassegnare il file mmaped (o le sue parti) in sola lettura una volta.

#include <sys/mman.h> 

int madvise(void *start, size_t length, int advice);

Il consiglio è indicato nel parametro consiglio che può essere

MADV_SEQUENTIAL 

Si aspettano riferimenti alle pagine in ordine sequenziale.     (Quindi, le pagine della gamma data possono essere aggressivo leggere in anticipo,     e può essere liberato subito dopo vi si accede.)

Portabilità:   posix_madvise e posix_fadvise fa parte opzione avanzata REALTIME di IEEE Std di 1003.1, 2004. E le costanti saranno POSIX_MADV_SEQUENTIAL e POSIX_FADV_SEQUENTIAL.

top ha molte colonne relativi alla memoria. La maggior parte di essi sono basati sulla dimensione dello spazio di memoria associato al processo; comprese le eventuali librerie condivise, scambiato RAM e spazio mmapped.

Controlla la colonna RES, questo è legato alla RAM fisica attualmente in uso. Credo (ma non sicuro) che includerebbe la RAM utilizzata per 'cache' il file mmap'ped

Si può essere stato offerto il consiglio sbagliato.

file mappati in memoria (mmap) useranno sempre di più memoria, come si analizza attraverso di loro. Quando la memoria fisica diventa basso, il kernel annullare la mappatura sezioni del file dalla memoria fisica in base alla sua LRU (almeno di recente utilizzato) algoritmo. Ma la LRU è anche globale. L'IFR può anche forzare altri processi per scambiare pagine su disco, e ridurre la cache del disco. Questo può avere un grave effetto negativo sulle prestazioni su altri processi e il sistema nel suo complesso.

Se stai leggendo in modo lineare attraverso i file, come contare il numero di linee, mmap è una cattiva scelta, come si riempirà la memoria fisica prima che la memoria di rilascio al sistema. Sarebbe meglio usare metodi di I / O tradizionali quali flusso o leggere in un blocco alla volta. Quel ricordo modo può essere rilasciato subito dopo.

Se si sta a caso l'accesso a file, mmap è una scelta va bene. Ma non è ottimale in quanto si sarebbe ancora in affidamento algoritmo LRU generale del kernel, ma è più veloce da usare rispetto a scrivere il meccanismo di caching.

In generale, Non consiglierei mai a nessuno usa mmap, ad eccezione di alcuni casi limite le prestazioni estreme - come l'accesso al file da più processi o thread allo stesso tempo, o quando il file è piccolo in relazione alla quantità di libero disponibile la memoria.

"allocare l'intero file in memoria" fonde due questioni. Uno è la quantità di memoria virtuale si assegnano; l'altra è che le parti del file vengono letti dal disco in memoria. Qui si assegnano spazio sufficiente per contenere l'intero file. Tuttavia, solo le pagine che si tocca saranno effettivamente modificati su disco. E, essi saranno cambiati in modo corretto, non importa cosa succede con il processo, una volta che avete aggiornato i byte nella memoria che mmap allocata per voi. È possibile allocare meno memoria per la mappatura solo una sezione del file alla volta utilizzando la "dimensione" e "Offset" parametri di mmap. Poi si deve gestire una finestra nel file voi stessi mappatura e unmapping, forse spostando la finestra attraverso il file. Allocare una grossa fetta di memoria richiede tempo apprezzabile. Questo può introdurre un ritardo imprevisto nell'applicazione. Se il processo è già molta memoria, la memoria virtuale può essere diventata frammentata e può essere impossibile trovare una abbastanza grande pezzo di un file di grandi dimensioni, al momento si chiede. Può quindi necessario cercare di fare la mappatura il più presto possibile, o per usare una certa strategia per mantenere una abbastanza grande pezzo di memoria disponibile fino a quando ne avete bisogno.

Tuttavia, visto che si specifica che è necessario analizzare il file, perché non evitare questo interamente da organizzare il vostro parser di operare su un flusso di dati? Poi il più avrete bisogno è un po 'look-ahead e un po' di storia, invece di aver bisogno di mappare pezzi discreti del file nella memoria.

Il sistema cercherà sicuramente di mettere tutti i dati nella memoria fisica. Cosa si può risparmiare è swap.

È necessario specificare una dimensione più piccola rispetto alla dimensione totale del file nella chiamata mmap, se non si desidera che l'intero file mappato in memoria in una sola volta. Utilizzando il parametro offset, e una dimensione più piccola, è possibile mappare in "finestre" del file più grande, un pezzo alla volta.

Se la vostra analisi è un singolo passaggio attraverso il file, con lookback minimo o guardare in avanti, allora non realmente guadagnare nulla utilizzando mmap invece di libreria standard buffer di I / O. Nell'esempio hai dato di contare le nuove righe nel file, sarebbe altrettanto velocemente di farlo con fread (). Suppongo che la vostra analisi reale è più complessa, però.

Se avete bisogno di leggere da più di una parte del file alla volta, dovrete gestire più regioni mmap, che possono rapidamente complicarsi.

Un po 'fuori tema.

Non del tutto d'accordo con la risposta di Marco. In realtà è più veloce di mmap fread.

Nonostante approfittando di tampone rigido del sistema, fread ha anche un buffer interno, e in aggiunta, i dati verranno copiati nel buffer fornito dall'utente come viene chiamato.

Al contrario, mmap solo restituire un puntatore al buffer del sistema. Quindi c'è un due-memory-copie-risparmio .

Ma usando mmap un po 'pericoloso. È necessario assicurarsi che il puntatore non passa mai di file, o ci sarà un errore di segmento . Mentre in questo caso fread solo restituisce zero .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top