REMARQUE: je suppose que votre machine est équipée d'une unité de cartographie de mémoire (MMU). Il existe une version Linux (µClinux) qui n'exige pas de MMU, et cette réponse ne s'applique pas là.
Qu'est-ce qu'un MMU? C'est une partie matérielle du processeur et / ou du contrôleur de mémoire. Comprendre la liaison de bibliothèque partagée ne vous oblige pas à comprendre exactement le fonctionnement d’une MMU, c’est qu’une telle unité permet de faire la différence entre les adresses de mémoire logiques (celles utilisées par les programmes) et les adresses physiques.adresses mémoire (celles réellement présentes sur le bus mémoire). La mémoire est divisée en pages, généralement de 4 Ko sous Linux. Avec 4k pages, les adresses logiques 0 à 4095 sont la page 0, les adresses logiques 4096 à 8191 sont la page 1, etc. La MMU les mappe sur des pages physiques de RAM et chaque page logique peut être mappée sur 0 ou 1 pages physiques. Une page physique donnée peut correspondre à plusieurs pages logiques (c’est ainsi que la mémoire est partagée: plusieurs pages logiques correspondent à la même page physique). Notez que cela s'applique quel que soit le système d'exploitation. c'est une description du matériel.
Au changement de processus, le noyau modifie les mappages de pages MMU, de sorte que chaque processus dispose de son propre espace. L'adresse 4096 dans le processus 1000 peut être (et est généralement) complètement différente de l'adresse 4096 dans le processus 1001.
Presque chaque fois que vous voyez une adresse, c’est une adresse logique. Les programmes d’espace utilisateur ne traitent presque jamais d’adresses physiques.
Maintenant, il y a aussi plusieurs façons de construire des bibliothèques. Supposons qu'un programme appelle la fonction foo()
dans la bibliothèque. La CPU ne sait rien des symboles, ni des appels de fonction. Elle sait comment accéder à une adresse logique et exécuter le code trouvé. Cela peut être fait de différentes manières (et des choses similaires s'appliquent lorsqu'une bibliothèque accède à ses propres données globales, etc.):
- Il pourrait coder en dur une adresse logique pour l'appeler. Cela nécessite que la bibliothèque soit toujours chargée à la même adresse logique. Si deux bibliothèques nécessitent la même adresse, la liaison dynamique échoue et vous ne pouvez pas lancer le programme. Les bibliothèques peuvent nécessiter d'autres bibliothèques. Par conséquent, chaque bibliothèque du système doit posséder des adresses logiques uniques. C'est très rapide, cependant, si cela fonctionne. (Voici comment a.out a fait les choses, et le genre de configuration que fait la liaison préliminaire, en quelque sorte).
- Il pourrait coder en dur une fausse adresse logique et demander à l'éditeur de liens dynamique de modifier celle qui convient lors du chargement de la bibliothèque. Cela demande beaucoup de temps lors du chargement des bibliothèques, mais après cela, c'est très rapide.
- Cela pourrait ajouter une couche d'indirection: utilisez un registre de la CPU pour contenir l'adresse logique à laquelle la bibliothèque est chargée, puis accédez à tout comme un décalage par rapport à ce registre. Ceci impose un coût de performance sur chaque accès.
Pratiquement personne n’utilise plus le logiciel n ° 1, du moins pas sur les systèmes polyvalents. Conserver cette liste d'adresses logiques unique est impossible sur les systèmes 32 bits (il n'y en a pas assez) et un cauchemar administratif sur les systèmes 64 bits. Une sorte de pré-liaison fait cela, cependant, système par système.
Que N ° 2 ou N ° 3 soit utilisé dépend de si la bibliothèque a été construite avec l' -fPIC
option de GCC (code indépendant de la position). Le n ° 2 est sans, le n ° 3 est avec. Généralement, les bibliothèques sont construites avec -fPIC
, donc # 3 est ce qui se passe.
Pour plus de détails, voir Comment écrire des bibliothèques partagées (PDF) de Ulrich Drepper .
Donc, enfin, on peut répondre à votre question:
- Si la bibliothèque est construite avec
-fPIC
(comme il se doit presque certainement), la grande majorité des pages sont exactement les mêmes pour chaque processus qui les charge. Vos processus a
et b
risquent de charger la bibliothèque à différentes adresses logiques, mais celles-ci pointeront sur les mêmes pages physiques: la mémoire sera partagée. De plus, les données dans la RAM correspondent exactement à celles du disque, elles ne peuvent donc être chargées que lorsque le gestionnaire de défauts de page en a besoin.
- Si la bibliothèque est construite sans
-fPIC
, il s'avère que la plupart des pages de la bibliothèque nécessiteront des modifications de liens et seront différentes. Par conséquent, elles doivent être des pages physiques séparées (car elles contiennent des données différentes). Cela signifie qu'ils ne sont pas partagés. Les pages ne correspondent pas à ce qui est sur le disque, donc je ne serais pas surpris si toute la bibliothèque est chargée. Il peut bien entendu être ultérieurement échangé sur disque (dans le fichier d'échange).
Vous pouvez examiner cela avec l' pmap
outil ou directement en archivant divers fichiers /proc
. Par exemple, voici une sortie (partielle) de pmap -x
deux s différents nouvellement créés bc
. Notez que les adresses indiquées par pmap sont généralement des adresses logiques:
pmap -x 14739
Address Kbytes RSS Dirty Mode Mapping
00007f81803ac000 244 176 0 r-x-- libreadline.so.6.2
00007f81803e9000 2048 0 0 ----- libreadline.so.6.2
00007f81805e9000 8 8 8 r---- libreadline.so.6.2
00007f81805eb000 24 24 24 rw--- libreadline.so.6.2
pmap -x 17739
Address Kbytes RSS Dirty Mode Mapping
00007f784dc77000 244 176 0 r-x-- libreadline.so.6.2
00007f784dcb4000 2048 0 0 ----- libreadline.so.6.2
00007f784deb4000 8 8 8 r---- libreadline.so.6.2
00007f784deb6000 24 24 24 rw--- libreadline.so.6.2
Vous pouvez voir que la bibliothèque est chargée en plusieurs parties et pmap -x
vous donne des détails sur chacune d’elles séparément. Vous remarquerez que les adresses logiques sont différentes entre les deux processus. vous vous attendriez raisonnablement à ce qu'ils soient identiques (puisque le même programme est en cours d'exécution et que les ordinateurs sont généralement prévisibles), mais il existe une fonction de sécurité appelée randomisation de la disposition de l'espace d'adressage qui les aléatoirement.
La différence de taille (kilo-octets) et de taille résidente (RSS) indique que le segment entier de la bibliothèque n'a pas été chargé. Enfin, vous pouvez voir que, pour les mappages plus grands, sale est 0, ce qui signifie qu'il correspond exactement à ce qui se trouve sur le disque.
Vous pouvez le relancer avec pmap -XX
, et cela vous montrera - en fonction de la version du noyau que vous exécutez, car la sortie -XX varie selon la version du noyau - que le premier mappage a un Shared_Clean
176, ce qui correspond exactement à RSS
. Shared
mémoire signifie que les pages physiques sont partagées par plusieurs processus et, étant donné que cela correspond au RSS, cela signifie que toute la bibliothèque en mémoire est partagée (consultez la section Voir aussi ci-dessous pour plus d'explications sur les domaines partagé et privé):
pmap -XX 17739
Address Perm Offset Device Inode Size Rss Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Referenced Anonymous AnonHugePages Swap KernelPageSize MMUPageSize Locked VmFlagsMapping
7f784dc77000 r-xp 00000000 fd:00 1837043 244 176 19 176 0 0 0 176 0 0 0 4 4 0 rd ex mr mw me sd libreadline.so.6.2
7f784dcb4000 ---p 0003d000 fd:00 1837043 2048 0 0 0 0 0 0 0 0 0 0 4 4 0 mr mw me sd libreadline.so.6.2
7f784deb4000 r--p 0003d000 fd:00 1837043 8 8 8 0 0 0 8 8 8 0 0 4 4 0 rd mr mw me ac sd libreadline.so.6.2
7f784deb6000 rw-p 0003f000 fd:00 1837043 24 24 24 0 0 0 24 24 24 0 0 4 4 0 rd wr mr mw me ac sd libreadline.so.6.2
Voir également
-fPIC
utilisation a complètement changé il ya quelque temps)?