GNU/Linux >> Tutoriels Linux >  >> Linux

Chargement des bibliothèques partagées et utilisation de RAM ?

Je m'interroge sur la façon dont Linux gère les bibliothèques partagées. (en fait, je parle de Maemo Fremantle, une distribution basée sur Debian publiée en 2009 et fonctionnant sur 256 Mo de RAM).

Supposons que nous ayons deux exécutables liés à libQtCore.so.4 et utilisant ses symboles (en utilisant ses classes et ses fonctions). Par souci de simplicité, appelons-les a et b . Nous supposons que les deux exécutables sont liés aux mêmes bibliothèques.

D'abord, nous lançons a . La bibliothèque doit être chargée. Est-il chargé en totalité ou est-il chargé en mémoire uniquement dans la partie requise (comme nous n'utilisons pas chaque classe, seul le code concernant les classes utilisées est chargé) ?

Puis on lance b . Nous supposons que a est toujours en cours d'exécution. b lie également à libQtCore.so.4 et utilise certaines des classes qui a utilise, mais aussi certains qui ne sont pas utilisés par a . La bibliothèque sera-t-elle chargée deux fois (séparément pour a et séparément pour b ) ? Ou utiliseront-ils le même objet déjà en RAM. Si b n'utilise aucun nouveau symbole et a est déjà en cours d'exécution, la RAM utilisée par les bibliothèques partagées augmentera-t-elle ? (Ou la différence sera-t-elle insignifiante)

Réponse acceptée :

REMARQUE :Je vais supposer que votre machine dispose d'une unité de mappage de mémoire (MMU). Il existe une version Linux (µClinux) qui ne nécessite pas de MMU, et cette réponse ne s'applique pas ici.

Qu'est-ce qu'un MMU ? C'est du matériel - une partie du processeur et/ou du contrôleur de mémoire. Comprendre la liaison de bibliothèque partagée ne vous oblige pas à comprendre exactement comment fonctionne une MMU, juste qu'une MMU permet qu'il y ait une différence entre logique adresses mémoire (celles utilisées par les programmes) et physiques adresses mémoire (celles réellement présentes sur le bus mémoire). La mémoire est décomposée en pages, généralement de taille 4K 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 généralement être mappée sur 0 ou 1 pages physiques. Une même page physique peut correspondre à plusieurs pages logiques (c'est ainsi que la mémoire est partagée :plusieurs pages logiques correspondent à une même page physique). Notez que cela s'applique quel que soit le système d'exploitation ; c'est une description du matériel.

Lors du changement de processus, le noyau modifie les mappages de pages MMU, de sorte que chaque processus dispose de son propre espace. L'adresse 4096 du processus 1000 peut être (et est généralement) complètement différente de l'adresse 4096 du 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 existe également plusieurs façons de créer des bibliothèques. Disons qu'un programme appelle la fonction foo() dans la bibliothèque. Le processeur ne sait rien des symboles ou des appels de fonction en fait - il sait juste comment sauter à une adresse logique et exécuter le code qu'il y trouve. Il y a plusieurs façons de procéder (et des choses similaires s'appliquent lorsqu'une bibliothèque accède à ses propres données globales, etc.) :

  1. Il pourrait coder en dur une adresse logique à laquelle l'appeler. Cela nécessite que la bibliothèque toujours être chargé exactement à 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, donc cela nécessite essentiellement que chaque bibliothèque du système ait des adresses logiques uniques. C'est très rapide, cependant, si cela fonctionne. (C'est comme ça que a.out a fait les choses, et le genre de configuration que fait la pré-liaison, en quelque sorte).
  2. Cela pourrait coder en dur une fausse adresse logique et demander à l'éditeur de liens dynamique de modifier la bonne adresse lors du chargement de la bibliothèque. Cela prend un peu de temps lors du chargement des bibliothèques, mais ensuite c'est très rapide.
  3. Cela pourrait ajouter une couche d'indirection :utiliser un registre CPU pour contenir l'adresse logique à laquelle la bibliothèque est chargée, puis accéder à tout comme un décalage à partir de ce registre. Cela impose un coût de performance à chaque accès.
Connexes :Linux - cp perd les métadonnées du fichier ?

Pratiquement plus personne n'utilise #1, du moins pas sur les systèmes à usage général. Garder cette liste d'adresses logiques unique est impossible sur les systèmes 32 bits (il n'y en a pas assez pour tout le monde) et un cauchemar administratif sur les systèmes 64 bits. La pré-liaison fait cela, cependant, sur une base par système.

Que #2 ou #3 soit utilisé dépend si la bibliothèque a été construite avec -fPIC de GCC (code indépendant de la position). #2 est sans, #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, consultez le document How to Write Shared Libraries (PDF) d'Ulrich Drepper.

Donc, enfin, votre question peut être répondue :

  1. Si la bibliothèque est construite avec -fPIC (comme cela devrait presque certainement être le cas), la grande majorité des pages sont exactement les mêmes pour chaque processus qui les charge. Vos processus a et b peut bien charger la bibliothèque à des adresses logiques différentes, mais celles-ci pointeront vers les mêmes pages physiques :la mémoire sera partagée. De plus, les données dans la RAM correspondent exactement à ce qui se trouve sur le disque, de sorte qu'elles ne peuvent être chargées qu'en cas de besoin par le gestionnaire de défauts de page.
  2. 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, il doit s'agir de pages physiques distinctes (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 était chargée. Il peut bien sûr être ensuite échangé sur le disque (dans le fichier d'échange).

Vous pouvez examiner cela avec le pmap outil, ou directement en vérifiant divers fichiers dans /proc . Par exemple, voici une sortie (partielle) de pmap -x sur deux bc nouvellement créés différents s. Notez que les adresses affichées par pmap sont, en règle générale, 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 chacun 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 c'est le même programme qui s'exécute et que les ordinateurs sont généralement prévisibles comme ça), mais il existe une fonctionnalité de sécurité appelée randomisation de la disposition de l'espace d'adressage qui les randomise intentionnellement.

Vous pouvez voir à partir de la différence de taille (Ko) et de taille résidente (RSS) que le segment entier de la bibliothèque n'a pas été chargé. Enfin, vous pouvez voir que pour les mappages plus importants, dirty vaut 0, ce qui signifie qu'il correspond exactement à ce qui se trouve sur le disque.

Vous pouvez relancer avec pmap -XX , et il vous montrera, selon 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 de 176, ce qui correspond exactement au RSS . Shared la mémoire signifie que les pages physiques sont partagées entre plusieurs processus, et puisqu'elle correspond au RSS, cela signifie que toute la bibliothèque qui est en mémoire est partagée (consultez Voir aussi ci-dessous pour plus d'explications sur partagé ou 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 aussi

  • Obtenir des informations sur l'utilisation de la mémoire d'un processus à partir de /proc/pid/smaps pour une explication de tout ce qui est propre/dirty partagé/privé.
Connexes :Linux - Comment faire en sorte que sar s'affiche pour la veille ?
Linux
  1. Erreur lors du chargement des bibliothèques partagées libcrypto.so.1.1 – OpenSSL [Réparer]

  2. Mesurer l'utilisation de RAM d'un programme ?

  3. "quel" équivalent pour les bibliothèques partagées ?

  4. Introduction aux bibliothèques partagées Linux (comment créer des bibliothèques partagées)

  5. Suppression des bibliothèques partagées Linux

Bibliothèque partagée Jenkins :comment créer, configurer et utiliser

Contrôlez l'utilisation de la RAM et du CPU par Kodi en temps réel

Comment initialiser une bibliothèque partagée sous Linux

Erreur lors du chargement de la bibliothèque partagée (glew)

Ubuntu reconnaît l'exécutable en tant que bibliothèque partagée et ne l'exécutera pas en cliquant sur

conda.exe :erreur lors du chargement des bibliothèques partagées :libz.so.1