2010-08-19 4 views
13

J'essaie de savoir comment remapper les fichiers mappés en mémoire sur un Mac (quand je veux étendre l'espace disponible).Y a-t-il vraiment pas de plan à Darwin?

Je vois nos amis dans le monde Linux ont mremap mais je ne trouve pas une telle fonction dans les en-têtes sur mon Mac. /Developer/SDKs/MacOSX10.6.sdk/usr/include/sys/mman.h a ce qui suit:

  • mmap
  • mprotect
  • msync
  • munlock
  • munmap
  • mais pas mremap

man mremap confirme mes craintes.

Je suis actuellement à munmap et mmmap si je veux redimensionner la taille du fichier mappé, ce qui implique d'invalider toutes les pages chargées. Il doit y avoir un meilleur moyen. Sûrement? J'essaye d'écrire du code qui fonctionnera sur Mac OS X et Linux. Je pourrais me contenter d'une macro pour utiliser la meilleure fonction dans chaque cas si j'avais avait à mais je préfère le faire correctement.

Répondre

0

Vous pouvez tracer le fichier à une grande taille (en créant un trou) et le mmap tout. Si le fichier est persistant, je recommande de remplir le trou avec des appels d'écriture plutôt que d'écrire dans le mappage, sinon les blocs du fichier risquent d'être fragmentés inutilement sur le disque.

+0

Donc vous suggérez que je devrais allouer pour la plus grande taille possible que je pourrais jamais vouloir et remplir le trou? C'est une idée intéressante mais soit je cartographie le maximum d'adresses possible et je ne laisse plus d'adresses pour rien d'autre, soit j'en utilise un peu moins et je risque de manquer. De plus, cela ne serait pas multiplate-forme (comme indiqué dans ma question) car je ne pouvais pas garantir que certains systèmes de fichiers ne feraient pas disparaître toute la plage du fichier et gaspilleraient des gigaoctets. – Joe

+3

Vous n'avez même pas besoin de faire le fichier sur un disque de cette taille. Juste 'mmap' plus grand que la taille du fichier. Les accès au-delà de la fin du fichier se traduiront par 'SIGBUS', donc vous devrez le 'ftruncate' plus longtemps avant d'essayer d'accéder à de nouvelles parties via le' mmap', mais sinon c'est bon. –

0

Je n'ai aucune expérience avec le mappage de la mémoire, mais il semble que vous puissiez mapper temporairement le même fichier deux fois afin de développer le mappage sans rien perdre.

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); 
} 

La sortie est zxxxxxxxxxyyyyyy..... Je suppose que, si vous tapez sur cela, il peut être possible de manquer d'espace d'adressage plus rapidement qu'avec le mremap. Mais rien n'est garanti dans les deux cas, et d'un autre côté, il serait tout aussi sûr.

+1

Corrigez-moi si je me trompe, mais cela ne causerait-il pas beaucoup d'E/S supplémentaires sur mmap MAP_PRIVATE et mremap? En raison de MAP_SHARED rinçage écrit sur le disque? – Eloff

+0

@ Eloff: Le seul moyen est d'essayer et de voir. Ce post est très ancien et je n'ai jamais eu beaucoup d'incitation à effectuer l'expérience: vP. Il serait un peu surprenant de voir des flushs excessifs, puisque toute la mémoire est toujours mappée au moins une fois. Le système d'exploitation devrait seulement vider lorsque le dernier mappage est éliminé, non? – Potatoswatter

5

Si vous avez besoin de réduire la carte, juste munmap la partie à la fin que vous souhaitez supprimer.

Si vous avez besoin pour agrandir la carte, vous pouvez mmap le décalage approprié avec MAP_FIXED aux adresses juste au-dessus de la vieille carte, mais vous devez faire attention que vous ne mappez pas sur quelque chose d'autre qui est déjà là ..

Le texte ci-dessus en retrait barré est une idée terrible; MAP_FIXED est fondamentalement faux, sauf si vous savez déjà ce qu'il y a à l'adresse cible et que vous voulez le remplacer de façon atomique. Si vous essayez de mapper de façon opportuniste quelque chose de nouveau si la plage d'adresses est libre, vous devez utiliser mmap avec une adresse demandée mais sansMAP_FIXED et voir si elle réussit et vous donne l'adresse demandée; S'il réussit mais avec une adresse différente, vous voudrez démapper le nouveau mapping que vous venez de créer et supposer que l'allocation à l'adresse demandée n'était pas possible.

+0

L'ajout d'une région mappée supplémentaire risque-t-elle de ne pas pouvoir être assigné à cette adresse? – Joe

+0

Oui, c'est ce que je voulais prévenir. Mais je crois que MAP_FIXED sera toujours mappé par-dessus un mappage existant (détruisant le mappage existant) plutôt que d'échouer, ce qui est encore pire. –

1

Si vous développez en morceaux assez volumineux (par exemple, 64 Mo, mais cela dépend de la vitesse à laquelle il se développe), le coût d'invalidation de l'ancienne carte est négligeable. Comme toujours, benchmark avant d'assumer un problème.

Questions connexes