Les fichiers sont-ils ouverts par des processus chargés dans la RAM?

24

Les commandes , par exemple sed, sont des programmes et les programmes sont une logique codifiée dans un fichier et ces fichiers se trouvent quelque part sur le disque dur. Cependant, lorsque des commandes sont exécutées, une copie de leurs fichiers du disque dur est placée dans la RAM , où elles prennent vie et peuvent faire des choses et sont appelées processus .

Les processus peuvent utiliser d'autres fichiers, y lire ou y écrire, et s'ils le font, ces fichiers sont appelés fichiers ouverts. Il y a une commande pour répertorier tous les fichiers ouverts par tous les processus en cours d' exécution: lsof.

OK, donc ce que je me demande, c'est si la double vie d'une commande, une sur le disque dur, l'autre dans la RAM est également vraie pour d'autres types de fichiers, par exemple ceux qui n'ont pas de logique programmée, mais sont simplement des conteneurs pour Les données.

Mon hypothèse est que les fichiers ouverts par des processus sont également chargés dans la RAM. Je ne sais pas si c'est vrai, c'est juste une intuition.

S'il vous plaît, quelqu'un pourrait-il comprendre cela?

sharkant
la source

Réponses:

27

Cependant, lorsque des commandes sont exécutées, une copie de leurs fichiers depuis le disque dur est placée dans la RAM,

C'est faux (en général). Lorsqu'un programme est exécuté (via execve (2) ...), le processus (exécutant ce programme) change son espace d'adressage virtuel et le noyau reconfigure la MMU à cet effet. Lisez aussi la mémoire virtuelle . Notez que les programmes d'application peuvent changer leur espace d'adressage virtuel en utilisant mmap (2) & munmap& mprotect (2) , également utilisé par l' éditeur de liens dynamique (voir ld-linux (8) ). Voir aussi madvise (2) & posix_fadvise (2) & mlock (2) .

Les futures erreurs de page seront traitées par le noyau pour charger (paresseusement) les pages du fichier exécutable. Lisez aussi à propos de la raclée .

Le noyau maintient un grand cache de pages . Lisez également sur la copie sur écriture . Voir aussi readahead (2) .

OK, donc ce que je me demande, c'est si la double vie d'une commande, une sur le disque dur, l'autre dans la RAM est également vraie pour d'autres types de fichiers, par exemple ceux qui n'ont pas de logique programmée, mais sont simplement des conteneurs pour Les données.

Pour les appels système comme read (2) & write (2), le cache de page est également utilisé. Si les données à lire s'y trouvent, aucune E / S disque ne sera effectuée. Si le disque IO est nécessaire, les données lues seraient très probablement placées dans le cache de page. Donc, dans la pratique, si vous exécutez la même commande deux fois, il peut arriver qu'aucune E / S physique ne soit effectuée sur le disque la deuxième fois (si vous avez un ancien disque dur rotatif - pas un SSD - vous pourriez l'entendre; ou observez attentivement la LED de votre disque dur).

Je recommande de lire un livre comme Operating Systems: Three Easy Pieces (téléchargeable gratuitement, un fichier PDF par chapitre) qui explique tout cela.

Voir aussi Linux Ate Mes RAM commandes et courir comme xosview, top, htopou cat /proc/self/mapsou cat /proc/$$/maps(voir proc (5) ).

PS. Je me concentre sur Linux, mais d'autres systèmes d'exploitation ont également une mémoire virtuelle et un cache de pages.

Basile Starynkevitch
la source
35

Non, un fichier n'est pas lu automatiquement en mémoire en l'ouvrant. Ce serait terriblement inefficace. sed, par exemple, lit son entrée ligne par ligne, comme le font de nombreux autres outils Unix. Il doit rarement conserver plus que la ligne actuelle en mémoire.

Avec awkc'est la même chose. Il lit un enregistrement à la fois, qui par défaut est une ligne. Si vous stockez des parties des données d'entrée dans des variables, ce sera supplémentaire, bien sûr 1 .

Certaines personnes ont l'habitude de faire des choses comme

for line in $(cat file); do ...; done

Étant donné que le shell devra étendre la $(cat file)substitution de commande complètement avant d' exécuter même la première itération de la forboucle, ce sera lu toute la fileen mémoire (dans la mémoire utilisée par le shell d' exécuter la forboucle). C'est un peu idiot et aussi inélégant. Au lieu de cela, on devrait faire

while IFS= read -r line; do ...; done <file

Cela traitera fileligne par ligne (mais lisez bien Comprendre "IFS = read -r line" ).

Le traitement des fichiers ligne par ligne dans le shell n'est cependant que rarement nécessaire, car la plupart des utilitaires sont de toute façon orientés ligne (voir Pourquoi l'utilisation d'une boucle shell pour traiter du texte est-elle considérée comme une mauvaise pratique? ).

Je travaille en bioinformatique, et lors du traitement d'énormes quantités de données génomiques, je ne serais pas en mesure de faire grand-chose à moins de ne conserver que les bits des données qui étaient absolument nécessaires en mémoire. Par exemple, lorsque j'ai besoin de supprimer les bits de données qui pourraient être utilisés pour identifier des individus d'un ensemble de données de 1 téraoctet contenant des variantes d'ADN dans un fichier VCF (car ce type de données ne peut pas être rendu public), je le fais ligne par ligne traitement avec un awkprogramme simple (ceci est possible car le format VCF est orienté ligne). Je ne lis pas le fichier en mémoire, je ne le traite pas et je le réécris! Si le fichier était compressé, je le ferais passer zcatou gzip -d -c, qui, depuis le gziptraitement en continu des données, ne lirait pas non plus le fichier entier en mémoire.

Même avec des formats de fichiers qui ne sont pas orientés ligne, comme JSON ou XML, il existe des analyseurs de flux qui permettent de traiter des fichiers énormes sans tout stocker dans la RAM.

Avec les exécutables, c'est un peu plus compliqué car les bibliothèques partagées peuvent être chargées à la demande et / ou être partagées entre les processus (voir Chargement des bibliothèques partagées et utilisation de la RAM , par exemple).

La mise en cache est quelque chose que je n'ai pas mentionné ici. Il s'agit de l'utilisation de la RAM pour stocker des données fréquemment consultées. Les fichiers plus petits (par exemple les exécutables) peuvent être mis en cache par le système d'exploitation dans l'espoir que l'utilisateur leur fera de nombreuses références. Outre la première lecture du fichier, les accès ultérieurs seront effectués sur la RAM plutôt que sur le disque. La mise en cache, comme la mise en mémoire tampon des entrées et des sorties, est généralement largement transparente pour l'utilisateur et la quantité de mémoire utilisée pour mettre en cache les choses peut changer dynamiquement en fonction de la quantité de RAM allouée par les applications, etc.


1 Techniquement, la plupart des programmes lisent probablement une partie des données d'entrée à la fois, soit en utilisant une mise en mémoire tampon explicite, soit implicitement via la mise en mémoire tampon des bibliothèques d'E / S standard, puis en présentant cette partie ligne par ligne au code de l'utilisateur. Il est beaucoup plus efficace de lire un multiple de la taille de bloc du disque que par exemple un caractère à la fois. Cependant, cette taille de bloc sera rarement supérieure à une poignée de kilo-octets.

Kusalananda
la source
vous avez dit, il est possible de charger des bibliothèques partagées en RAM, est-il également possible de charger un fichier normal, qui ne contient que des données en RAM, même si cela n'a pas de sens?
sharkant
1
@sharkant Bien sûr. Il ne s'agit que d'ajouter des données à une variable (ou tableau, ou hachage, ou à toute structure de données fournie par la langue en question) jusqu'à ce que tout le fichier ait été stocké. Avec awk, { a[i++] = $0 }ajouterait toutes les lignes du fichier d'entrée au tableau a. Vous pouvez également rechercher la fonction C mmap(), mais son utilisation peut être un peu hors sujet ici.
Kusalananda
6
sed, awket d'autres programmes orientés ligne ne lisent pas une ligne à la fois dans la mémoire, car les fichiers en texte brut ne contiennent pas d'index de ligne, et les API du système de fichiers et le matériel de stockage de bas niveau lisent un ou plusieurs "secteurs" (généralement 512 ou 1024 octets) à la fois. Je serais surpris si moins de 8 Ko était lu en mémoire par le système d'exploitation avant le traitement de la première ligne.
Russell Borogove
5
Bien qu'un utilitaire comme sedne lise qu'une seule ligne à la fois dans la mémoire, il convient de mentionner que le système d'exploitation utilisera un ram gratuit pour mettre en cache les fichiers afin qu'ils soient accessibles rapidement. Si vous utilisez sedun fichier plus petit, il est possible que le système d'exploitation mette en cache l'intégralité du fichier en mémoire et que l'opération se fasse entièrement en RAM. Voir: en.wikipedia.org/wiki/Page_cache
Sean Dawson
5
@sharkant Il est utile d'avoir un fichier entièrement accessible en mémoire (voir l'autre réponse, mmap est le mot-clé appel système ici). Par exemple, un système de base de données voudrait généralement avoir, pour la facilité et la rapidité d'accès, la base de données entière ou au moins certains des indices mappés en mémoire. Cela ne signifie pas nécessairement que le tout est réellement en mémoire. L'OS est libre de "faire semblant" que le fichier est en mémoire. Il indique à l'application "ici, dans cette plage de mémoire est votre fichier", et seulement une fois la lecture terminée (tout comme lorsque le processus a été échangé), les données sont réellement lues.
Jonas Schäfer
5

Non. Bien que les concerts de RAM soient fantastiques ces jours-ci, il fut un temps où la RAM était une ressource très limitée (j'ai appris la programmation sur un VAX 11/750 avec 2 Mo de RAM) et la seule chose en RAM était un exécutable actif et des pages de données. des processus actifs et des données de fichier qui étaient dans le cache de tampon.
Le cache de tampon a été vidé et les pages de données ont été échangées. Et souvent à certains moments. Les pages exécutables en lecture seule ont été écrasées et les tables de pages marquées, donc si le programme touchait à nouveau ces pages, elles étaient paginées à partir du système de fichiers. Les données ont été paginées à partir du swap. Comme indiqué ci-dessus, la bibliothèque STDIO a extrait les données en blocs et a été obtenue par le programme selon les besoins: fgetc, fgets, fread, etc. Avec mmap, un fichier peut être mappé dans l'espace d'adressage d'un processus, comme c'est le cas avec objets de bibliothèque partagée ou même des fichiers normaux. Oui, vous pouvez avoir un certain degré de contrôle si c'est dans la RAM ou non (mlock), mais cela ne va que jusqu'à présent (voir la section code d'erreur de mlock).

Roger L.
la source
1
La déclaration «votre RAM va être trop petite pour vos fichiers» est vraie maintenant comme c'était dans les temps anciens de VAX.
Federico Poloni
1
@Federico_Poloni Pas tout à fait aussi vrai aujourd'hui. Chez mon dernier employeur, nous avions un PC de classe station de travail avec 1 To de RAM et seulement 0,5 To de disque dur. (Classe de problème: petites entrées, sorties moyennes, grandes matrices à accès aléatoire pendant le calcul).
nigel222