Les environnements POSIX offrent au moins deux façons d'accéder aux fichiers. Il y a l'appel standard du système open()
, read()
, write()
et amis, mais il y a aussi la possibilité d'utiliser mmap()
pour cartographier le fichier dans la mémoire virtuelle.
Quand est-il préférable d'utiliser l'un sur l'autre? Quels sont leurs avantages individuels qui méritent d'inclure deux interfaces?
Réponses:
mmap
est idéal si plusieurs processus accèdent aux données en lecture seule à partir du même fichier, ce qui est courant dans le type de systèmes de serveurs que j'écris.mmap
permet à tous ces processus de partager les mêmes pages de mémoire physique, économisant ainsi beaucoup de mémoire.mmap
permet également au système d'exploitation d'optimiser les opérations de pagination. Par exemple, considérons deux programmes; programmeA
qui lit dans un1MB
fichier dans un tampon créant avecmalloc
, et programme B quimmaps
le fichier 1 Mo en mémoire. Si le système d'exploitation doit échanger une partie deA
la mémoire, il doit écrire le contenu du tampon à échanger avant de pouvoir réutiliser la mémoire. DansB
le cas, toutesmmap
les pages non modifiées peuvent être réutilisées immédiatement car le système d'exploitation sait comment les restaurer à partir du fichier existant dont elles provenaientmmap
. (Le système d'exploitation peut détecter les pages non modifiées en marquant initialement lesmmap
pages inscriptibles comme étant en lecture seule et en détectant les erreurs de segmentation , comme dans la stratégie Copier en écriture ).mmap
est également utile pour la communication inter-processus . Vous pouvezmmap
utiliser un fichier en lecture / écriture dans les processus qui doivent communiquer, puis utiliser des primitives de synchronisation dans lammap'd
région (c'est à cela que sert l'MAP_HASSEMAPHORE
indicateur).Un endroit
mmap
peut être gênant si vous devez travailler avec de très gros fichiers sur une machine 32 bits. Cela est dû aummap
fait qu'il doit trouver un bloc d'adresses contigu dans l'espace d'adressage de votre processus qui est suffisamment grand pour s'adapter à toute la plage du fichier en cours de mappage. Cela peut devenir un problème si votre espace d'adressage devient fragmenté, où vous pourriez avoir 2 Go d'espace d'adressage libre, mais aucune plage individuelle ne peut s'adapter à un mappage de fichier de 1 Go. Dans ce cas, vous devrez peut-être mapper le fichier en plus petits morceaux que vous ne le souhaitez.Une autre gêne potentielle avec
mmap
en remplacement de la lecture / écriture est que vous devez commencer votre mappage sur des décalages de la taille de la page. Si vous voulez simplement obtenir des données en offsetX
vous devrez corriger cet offset pour qu'il soit compatible avecmmap
.Et enfin, lecture / écriture sont la seule façon que vous pouvez travailler avec certains types de fichiers.
mmap
ne peut pas être utilisé sur des choses comme les tuyaux et les tys .la source
MAP_HASSEMAPHORE
est spécifique à BSD.Un domaine où j'ai trouvé que mmap () n'était pas un avantage était lors de la lecture de petits fichiers (moins de 16 Ko). Le surdébit de page défaillant pour lire le fichier entier était très élevé par rapport à un simple appel système read (). C'est parce que le noyau peut parfois satisifier une lecture entièrement dans votre tranche de temps, ce qui signifie que votre code ne change pas. Avec un défaut de page, il semblait plus probable qu'un autre programme soit planifié, ce qui rendait l'opération de fichier plus latente.
la source
malloc
créer un morceau de mémoire et d'en faire 1read
. Cela permet d'avoir le même code qui gère les cartes mémoire malloc'ed.read
accès soit supérieure à celle de la manipulation de la mémoire virtuelle.mmap
doit mettre à jour 4 entrées dans le tableau des pages. Mais utiliserread
pour copier dans un tampon de 16 Ko implique également la mise à jour des entrées de table de 4 pages, sans oublier qu'il doit copier le 16 Ko dans l'espace utilisateur. Alors, pourriez-vous nous expliquer les différences d'opérations sur la table des pages et comment cela coûte plus chermmap
?mmap
a l'avantage lorsque vous avez un accès aléatoire sur de gros fichiers. Un autre avantage est que vous y accédez avec des opérations de mémoire (memcpy, arithmetic pointeur), sans vous soucier de la mise en mémoire tampon. Les E / S normales peuvent parfois être assez difficiles lorsque vous utilisez des tampons lorsque vous avez des structures plus grandes que votre tampon. Le code à gérer qui est souvent difficile à obtenir correctement, mmap est généralement plus facile. Cela dit, il existe certains pièges lorsque vous travaillez avecmmap
. Comme les gens l'ont déjà mentionné,mmap
sa mise en place est assez coûteuse, il vaut donc la peine de l'utiliser uniquement pour une taille donnée (variant d'une machine à l'autre).Pour les accès séquentiels purs au fichier, ce n'est pas toujours la meilleure solution, bien qu'un appel approprié à
madvise
puisse atténuer le problème.Vous devez être prudent avec les restrictions d'alignement de votre architecture (SPARC, itanium), avec les E / S en lecture / écriture, les tampons sont souvent correctement alignés et ne se coincent pas lors du déréférencement d'un pointeur casté.
Vous devez également faire attention à ne pas accéder en dehors de la carte. Cela peut facilement se produire si vous utilisez des fonctions de chaîne sur votre carte et que votre fichier ne contient pas de \ 0 à la fin. Cela fonctionnera la plupart du temps lorsque la taille de votre fichier n'est pas un multiple de la taille de la page car la dernière page est remplie de 0 (la zone mappée est toujours de la taille d'un multiple de la taille de votre page).
la source
En plus d'autres bonnes réponses, une citation de la programmation système Linux écrite par l'expert de Google, Robert Love:
la source
Le mappage de la mémoire offre un énorme avantage en termes de vitesse par rapport aux E / S traditionnelles. Il permet au système d'exploitation de lire les données du fichier source lorsque les pages du fichier mappé en mémoire sont touchées. Cela fonctionne en créant des pages défaillantes, que le système d'exploitation détecte, puis le système d'exploitation charge automatiquement les données correspondantes du fichier.
Cela fonctionne de la même manière que le mécanisme de pagination et est généralement optimisé pour les E / S à grande vitesse en lisant les données sur les limites et les tailles des pages système (généralement 4K) - une taille pour laquelle la plupart des caches du système de fichiers sont optimisés.
la source
pread
. Sur Solaris 9 Sparc (V890), l'accès au pread est entre 2 et 3 fois plus lent que celuimemcpy
du mmap. Mais vous avez raison, l'accès séquentiel n'est pas nécessairement plus rapide.Un avantage qui n'est pas encore répertorié est la possibilité de
mmap()
conserver un mappage en lecture seule en tant que pages propres . Si l'on alloue un tampon dans l'espace d'adressage du processus, alors utiliseread()
pour remplir le tampon à partir d'un fichier, les pages mémoire correspondant à ce tampon sont maintenant sales depuis qu'elles ont été écrites.Les pages sales ne peuvent pas être supprimées de la RAM par le noyau. S'il y a de l'espace de swap, ils peuvent être paginés pour swap. Mais cela coûte cher et sur certains systèmes, tels que les petits appareils embarqués avec uniquement une mémoire flash, il n'y a aucun échange du tout. Dans ce cas, le tampon sera bloqué dans la RAM jusqu'à la fin du processus, ou peut-être le restitue avec
madvise()
.Les
mmap()
pages non écrites sont propres. Si le noyau a besoin de RAM, il peut simplement les supprimer et utiliser la RAM dans laquelle les pages se trouvaient. . De la même manière, ils ont été peuplés en premier lieu.Cela ne nécessite pas plus d'un processus utilisant le fichier mappé pour être un avantage.
la source
read()
, les pages dans lesquelles les données sont finalement insérées n'ont aucun rapport avec le fichier dont elles peuvent provenir. Ils ne peuvent donc pas être écrits, sauf pour échanger de l'espace. Si un fichier l'estmmap()ed
et que le mappage est accessible en écriture (par opposition à la lecture seule) et écrit dans, cela dépend si le mappage étaitMAP_SHARED
ouMAP_PRIVATE
. Un mappage partagé peut / doit être écrit dans le fichier, mais pas un privé.