web-dev-qa-db-fra.com

Quand devrais-je utiliser mmap pour accéder aux fichiers?

Les environnements POSIX offrent au moins deux méthodes pour accéder aux fichiers. Il existe les appels système standard open(), read(), write() et amis, mais vous pouvez également utiliser mmap() pour mapper le fichier. dans la mémoire virtuelle.

Quand est-il préférable d'utiliser l'un par rapport à l'autre? Quels sont leurs avantages individuels qui méritent d'inclure deux interfaces?

256
Peter Burns

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ème serveur 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; programme A qui lit un fichier de 1 Mo dans un tampon créant avec malloc et programme B qui mappe le fichier de 1 Mo en mémoire. Si le système d'exploitation doit échanger une partie de la mémoire de A, il doit écrire le contenu de la mémoire tampon à échanger avant de pouvoir réutiliser la mémoire. Dans le cas de B, toutes les pages mmap'd non modifiées peuvent être réutilisées immédiatement, car le système d'exploitation sait comment les restaurer à partir du fichier existant à partir duquel elles ont été copiées. (Le système d'exploitation peut détecter les pages non modifiées en marquant initialement les pages mmap'd en écriture comme étant en lecture seule et en détectant les erreurs de segment, comme dans la stratégie de copie sur écriture).

mmap est également utile pour la communication entre processus. Vous pouvez mapper un fichier en lecture/écriture dans les processus devant communiquer, puis utiliser des primitives de synchronisation dans la région mmap'd (c'est à cela que sert l'indicateur MAP_HASSEMAPHORE).

Mmap peut être gênant si vous devez travailler avec de très gros fichiers sur une machine 32 bits. En effet, mmap doit trouver un bloc d'adresses contigu dans l'espace d'adressage de votre processus suffisamment volumineux 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é, vous pouvez ainsi disposer de 2 Go d'espace libre, mais aucune plage individuelle ne peut contenir un mappage de fichier de 1 Go. Dans ce cas, vous devrez peut-être mapper le fichier en morceaux plus petits 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 juste obtenir des données au décalage X, vous devrez corriger ce décalage afin qu'il soit compatible avec mmap.

Et enfin, la lecture/écriture est la seule façon dont vous pouvez travaillez avec certains types de fichiers. MMAP ne peut pas être utilisé sur des choses comme les pipes et les ttys.

284
Don Neufeld

Un domaine dans lequel mmap () n’était pas un avantage était celui de la lecture de petits fichiers (moins de 16K). La surcharge de page liée à la lecture de l'ensemble du fichier était très élevée par rapport à un simple appel système read (). Cela est dû au fait que le noyau peut parfois satisfaire entièrement une lecture dans votre tranche de temps, ce qui signifie que votre code ne disparaît pas. Avec un défaut de page, il semblait plus probable qu'un autre programme serait programmé, ce qui rendait l'opération de fichier avec une latence plus élevée.

62
Ben Combee

mmap a l'avantage lorsque vous avez un accès aléatoire aux gros fichiers. Un autre avantage est que vous y accédez avec des opérations de mémoire (mémoire, arithmétique de 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 vos structures sont plus grandes que votre tampon. Le code à traiter est souvent difficile à obtenir, mmap est généralement plus facile. Ceci dit, il y a certains pièges lorsque vous travaillez avec mmap. Comme on l'a déjà mentionné, la configuration de mmap est assez coûteuse. Il est donc intéressant de ne l'utiliser que 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 faire attention aux restrictions d'alignement de votre architecture (SPARC, itanium), avec lecture/écriture IO), les tampons sont souvent correctement alignés et ne sont pas interceptés lors du déréférencement d'un pointeur converti.

Vous devez également veiller à 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 si votre fichier ne contient pas un\0 à la fin. Cela fonctionnera la plupart du temps lorsque la taille de votre fichier ne représente pas un multiple de la taille de la page car la dernière page est remplie avec 0 (la zone mappée est toujours à la taille d'un multiple de la taille de votre page).

43

Outre d'autres réponses intéressantes, une citation de programmation système Linux écrite par l'expert de Google, Robert Love:

Avantages de mmap( )

Manipuler des fichiers via mmap( ) présente quelques avantages par rapport aux appels système read( ) et write( ) standard. Parmi eux:

  • La lecture et l'écriture dans un fichier mappé en mémoire évitent la copie superflue qui se produit lors de l'utilisation des appels système read( ) ou write( ), où les données doivent être copiées vers et depuis un espace utilisateur. tampon.

  • Mis à part les éventuels défauts de page, la lecture et l'écriture dans un fichier mappé en mémoire n'entraînent pas de surcharge d'appels système ni de changement de contexte. C'est aussi simple que d'accéder à la mémoire.

  • Lorsque plusieurs processus mappent le même objet en mémoire, les données sont partagées entre tous les processus. Les mappages en lecture seule et en écriture partagés sont partagés dans leur intégralité; les mappages privés en écriture ont leurs pages pas encore COW (copie sur écriture) partagées.

  • Rechercher autour de la cartographie implique des manipulations triviales de pointeur. L'appel système lseek( ) n'est pas nécessaire.

Pour ces raisons, mmap( ) est un choix judicieux pour de nombreuses applications.

Inconvénients de mmap( )

Il y a quelques points à garder à l'esprit lors de l'utilisation de mmap( ):

  • Les mappages de mémoire sont toujours un nombre entier de pages. Ainsi, la différence entre la taille du fichier de sauvegarde et un nombre entier de pages est "gaspillée" en tant qu'espace vide. Pour les petits fichiers, un pourcentage important de la cartographie peut être gaspillé. Par exemple, avec des pages de 4 Ko, un mappage de 7 octets gaspille 4 089 octets.

  • Les mappages de mémoire doivent correspondre à l'espace d'adressage du processus. Avec un espace d'adressage 32 bits, un très grand nombre de mappages de tailles différentes peut entraîner une fragmentation de l'espace d'adressage, ce qui rend difficile la recherche de grandes régions contiguës libres. Bien entendu, ce problème est beaucoup moins apparent avec un espace d'adressage 64 bits.

  • La création et la maintenance des mappages de mémoire et des structures de données associées à l'intérieur du noyau entraînent une surcharge. Cette surcharge est généralement évitée par la suppression de la double copie mentionnée dans la section précédente, en particulier pour les fichiers plus volumineux et fréquemment consultés.

Pour ces raisons, les avantages de mmap( ) se concrétisent surtout lorsque le fichier mappé est volumineux (de sorte que tout espace perdu représente un faible pourcentage du mappage total) ou lorsque la taille totale du fichier mappé est réduite. divisible de manière égale par la taille de la page (et donc pas d’espace perdu).

20
Miljen Mikic

Le mappage de la mémoire offre un avantage considérable 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éfectueuses, que le système d'exploitation détecte puis que le système d'exploitation charge automatiquement les données correspondantes à partir 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 rapides en lisant les données sur les limites et les tailles des pages système (généralement 4 Ko), une taille pour laquelle la plupart des caches de système de fichiers sont optimisés.

10
grover