2010-08-19 14 views
13

Sto cercando di rimappare i file mappati in memoria su un Mac (quando voglio espandere lo spazio disponibile).Non c'è davvero nessun mremap in Darwin?

Vedo che i nostri amici nel mondo Linux hanno mremap ma non riesco a trovare alcuna funzione nelle intestazioni sul mio Mac. /Developer/SDKs/MacOSX10.6.sdk/usr/include/sys/mman.h ha il seguente:

  • mmap
  • mprotect
  • msync
  • munlock
  • munmap
  • ma nessuno mremap

man mremap conferma le mie paure.

Attualmente sto avendo munmap e mmmap se voglio ridimensionare la dimensione del file mappato, che comporta l'invalidazione di tutte le pagine caricate. Ci deve essere un modo migliore. Certamente?

Sto provando a scrivere codice che funzionerà su Mac OS X e Linux. Potrei accontentarsi di una macro per utilizzare la migliore funzione in ogni caso se I avesse ma preferirei farlo correttamente.

risposta

0

È possibile eseguire il ftruncate del file su una grande dimensione (creando un foro) e mmap tutto. Se il file è persistente, ti consiglio di riempire il buco con le chiamate di scrittura anziché scrivere nella mappatura, altrimenti i blocchi del file potrebbero essere frammentati inutilmente sul disco.

+0

Quindi stai suggerendo che dovrei allocare per la dimensione più grande possibile che potrei mai volere e riempire il buco? È un'idea interessante ma o mapperò il massimo possibile di indirizzi e non lascerò più indirizzi per nient'altro o ne uso una quantità minore e correrò il rischio di finire. Inoltre, questo non sarebbe multipiattaforma (come indicato nella mia domanda) poiché non potevo garantire che alcuni filesystem non azzerassero effettivamente l'intero intervallo del file e sprecassero gigabyte. – Joe

+3

Non è nemmeno necessario rendere il file su disco così grande. Solo 'mmap' più grande della dimensione del file. Gli accessi oltre la fine del file risulteranno in 'SIGBUS', quindi è necessario' ftruncate' più a lungo prima di provare ad accedere a nuove parti tramite 'mmap', ma per il resto va bene. –

0

Non ho esperienza con la mappatura della memoria, ma sembra che sia possibile mappare temporaneamente lo stesso file due volte per espandere la mappatura senza perdere nulla.

int main() { 
    int fd; 
    char *fp, *fp2, *pen; 

     /* create 1K file */ 
    fd = open("mmap_data.txt", O_RDWR | O_CREAT, 0777); 
    lseek(fd, 1000, SEEK_SET); 
    write(fd, "a", 1); 

     /* map and populate it */ 
    fp = mmap(NULL, 1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 
    pen = memset(fp, 'x', 1000); 

     /* expand to 8K and establish overlapping mapping */ 
    lseek(fd, 8000, SEEK_SET); 
    write(fd, "b", 1); 
    fp2 = mmap(NULL, 7000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 

     /* demonstrate that mappings alias */ 
    *fp = 'z'; 
    printf("%c ", *fp2); 

     /* eliminate first mapping */ 
    munmap(fp, 1000); 

     /* populate second mapping */ 
    pen = memset(fp2+10, 'y', 7000); 

     /* wrap up */ 
    munmap(fp2, 7000); 
    close(fd); 
    printf("%d\n", errno); 
} 

L'uscita è zxxxxxxxxxyyyyyy.....

Suppongo che, se si blocca su questo, potrebbe essere possibile esaurire lo spazio indirizzo più veloce di con mremap. Ma nulla è garantito in entrambi i casi e, d'altro canto, potrebbe essere altrettanto sicuro.

+1

Correggetemi se ho torto, ma questo non causerebbe un sacco di IO in più su mmap MAP_PRIVATE e mremap? A causa del flushing MAP_SHARED scrive sul disco? – Eloff

+0

@Eloff: l'unico modo è provare e vedere. Questo post è molto vecchio e non ho mai avuto molti incentivi per eseguire l'esperimento: vP. Sarebbe un po 'sorprendente vedere un eccesso di colore, poiché tutta la memoria viene sempre mappata almeno una volta. Il sistema operativo dovrebbe svuotare solo quando viene eliminata l'ultima mappatura, giusto? – Potatoswatter

5

Se è necessario ridurre la mappa, solo munmap la parte alla fine che si desidera rimuovere.

Se è necessario ingrandire la mappa, è possibile mmap il corretto di offset con MAP_FIXED agli indirizzi appena sopra la vecchia mappa, ma è necessario fare attenzione che non si mappa su qualcos'altro che è già lì ..

Il testo sopra indicato è una pessima idea; MAP_FIXED è fondamentalmente sbagliato a meno che non si sappia già quale sia l'indirizzo di destinazione e si desidera sostituirlo atomicamente. Se stai cercando di mappare opportunisticamente qualcosa di nuovo se l'intervallo di indirizzi è libero, devi utilizzare mmap con un indirizzo richiesto ma senzaMAP_FIXED e vedere se ci riesce e ti dà l'indirizzo richiesto; se riesce, ma con un indirizzo diverso, dovrai rimuovere la mappatura della nuova mappatura appena creata e assumere che l'assegnazione all'indirizzo richiesto non sia possibile.

+0

Non aggiungere una regione mappata in più rischia di non essere in grado di assegnare a quell'indirizzo? – Joe

+0

Sì, questo è quello che stavo avvertendo. Ma credo che 'MAP_FIXED' mapperà sempre sopra una mappatura esistente (distruggendo la mappatura esistente) piuttosto che fallendo, il che è anche peggiore. –

1

Se si espandono blocchi di dimensioni sufficienti (ad esempio, 64 MB, ma dipende dalla velocità con cui cresce), il costo di invalidare la vecchia mappa è trascurabile. Come sempre, benchmark prima di assumere un problema.