HINWEIS: Ich gehe davon aus, dass Ihr Computer über eine Memory Mapping Unit (MMU) verfügt. Es gibt eine Linux-Version (µClinux), für die keine MMU erforderlich ist, und diese Antwort gilt dort nicht.
Was ist eine MMU? Dies ist Hardware - ein Teil des Prozessors und / oder des Speichercontrollers. Um die Verknüpfung von gemeinsam genutzten Bibliotheken zu verstehen, müssen Sie nicht genau wissen, wie eine MMU funktioniert, nur dass eine MMU einen Unterschied zwischen logischen Speicheradressen (die von Programmen verwendet werden) und physischen Adressen zulässtSpeicheradressen (die tatsächlich auf dem Speicherbus vorhandenen). Der Arbeitsspeicher ist in Seiten unterteilt, die unter Linux normalerweise 4 KB groß sind. Bei 4k-Seiten sind die logischen Adressen 0 bis 4095 Seite 0, die logischen Adressen 4096 bis 8191 Seite 1 usw. Die MMU ordnet diese physischen Seiten des RAM zu, und jede logische Seite kann normalerweise 0 oder 1 physischen Seiten zugeordnet werden. Eine bestimmte physische Seite kann mehreren logischen Seiten entsprechen (so wird der Speicher gemeinsam genutzt: Mehrere logische Seiten entsprechen derselben physischen Seite). Beachten Sie, dass dies unabhängig vom Betriebssystem gilt. Es ist eine Beschreibung der Hardware.
Beim Prozesswechsel ändert der Kernel die MMU-Seitenzuordnungen, sodass jeder Prozess seinen eigenen Speicherplatz hat. Die Adresse 4096 in Prozess 1000 kann sich von der Adresse 4096 in Prozess 1001 vollständig unterscheiden (und ist dies normalerweise).
So ziemlich immer, wenn Sie eine Adresse sehen, ist es eine logische Adresse. User-Space-Programme beschäftigen sich kaum mit physikalischen Adressen.
Es gibt jetzt auch mehrere Möglichkeiten, Bibliotheken zu erstellen. Angenommen, ein Programm ruft die Funktion foo()
in der Bibliothek auf. Die CPU weiß nichts über Symbole oder Funktionsaufrufe - sie weiß nur, wie sie zu einer logischen Adresse springt und den dort gefundenen Code ausführt. Es gibt verschiedene Möglichkeiten, dies zu tun (und ähnliche Möglichkeiten, wenn eine Bibliothek auf ihre eigenen globalen Daten usw. zugreift):
- Es könnte eine logische Adresse, unter der es aufgerufen werden kann, fest codieren. Dies erfordert, dass die Bibliothek immer an genau der gleichen logischen Adresse geladen wird. Wenn zwei Bibliotheken dieselbe Adresse benötigen, schlägt die dynamische Verknüpfung fehl und Sie können das Programm nicht starten. Bibliotheken können andere Bibliotheken erfordern, weshalb grundsätzlich jede Bibliothek im System eindeutige logische Adressen haben muss. Es ist jedoch sehr schnell, wenn es funktioniert. (So hat a.out die Dinge gemacht, und die Art der Einrichtung, die das Prelinking macht, irgendwie).
- Es könnte eine gefälschte logische Adresse fest codieren und den dynamischen Linker anweisen, beim Laden der Bibliothek die richtige zu bearbeiten. Dies kostet einiges an Zeit beim Laden der Bibliotheken, ist danach aber sehr schnell.
- Es könnte eine Indirektionsebene hinzufügen: Verwenden Sie ein CPU-Register , um die logische Adresse zu speichern, unter der die Bibliothek geladen wird, und greifen Sie dann auf alles als Offset von diesem Register aus zu. Dies verursacht bei jedem Zugriff Leistungskosten.
Ziemlich niemand benutzt mehr die Nummer 1, zumindest nicht auf Allzwecksystemen. Auf 32-Bit-Systemen ist es unmöglich, diese eindeutige logische Adressliste beizubehalten (es gibt nicht genug, um sie zu umgehen), und auf 64-Bit-Systemen ist dies ein administrativer Albtraum. Eine Vorverknüpfung erledigt dies jedoch auf Systembasis.
Ob # 2 oder # 3 verwendet wird, hängt davon ab, ob die Bibliothek mit der -fPIC
Option GCC (Position Independent Code) erstellt wurde. # 2 ist ohne, # 3 ist mit. Im Allgemeinen werden Bibliotheken mit erstellt -fPIC
, also ist # 3 das, was passiert.
Weitere Informationen finden Sie in Ulrich Dreppers How to Write Shared Libraries (PDF) .
So kann endlich Ihre Frage beantwortet werden:
- Wenn die Bibliothek mit
-fPIC
(wie es mit ziemlicher Sicherheit sein sollte) erstellt wird, ist die überwiegende Mehrheit der Seiten für jeden Prozess, der sie lädt, genau gleich. Ihre Prozesse a
und b
gut kann die Bibliothek in unterschiedlichen logischen Adressen laden, aber die auf die gleichen physischen Seiten zeigen wird: der Speicher gemeinsam genutzt wird. Darüber hinaus stimmen die Daten im RAM genau mit den Daten auf der Festplatte überein, sodass sie nur geladen werden können, wenn sie vom Seitenfehler-Handler benötigt werden.
- Wenn die Bibliothek ohne erstellt wird
-fPIC
, müssen die meisten Seiten der Bibliothek über Verknüpfungen bearbeitet werden und unterscheiden sich. Daher müssen sie separate physische Seiten sein (da sie unterschiedliche Daten enthalten). Das heißt, sie werden nicht geteilt. Die Seiten stimmen nicht mit denen auf der Festplatte überein, daher wäre ich nicht überrascht, wenn die gesamte Bibliothek geladen wäre. Es kann natürlich nachträglich auf die Festplatte ausgelagert werden (in der Auslagerungsdatei).
Sie können dies mit dem pmap
Tool oder direkt durch Einchecken verschiedener Dateien überprüfen /proc
. Hier ist zum Beispiel eine (teilweise) Ausgabe von pmap -x
zwei verschiedenen neu erzeugten bc
s. Beachten Sie, dass die von pmap angezeigten Adressen normalerweise logische Adressen sind:
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
Sie können sehen, dass die Bibliothek in mehreren Teilen geladen ist, und pmap -x
Sie erhalten Details zu jedem Teil separat. Sie werden feststellen, dass sich die logischen Adressen zwischen den beiden Prozessen unterscheiden. Sie würden vernünftigerweise erwarten, dass sie gleich sind (da dasselbe Programm ausgeführt wird und Computer normalerweise so vorhersehbar sind), aber es gibt eine Sicherheitsfunktion namens Adressraum-Layout-Randomisierung , die sie absichtlich zufällig anordnet.
Sie können anhand des Unterschieds in der Größe (KB) und der residenten Größe (RSS) erkennen, dass nicht das gesamte Bibliothekssegment geladen wurde. Schließlich können Sie sehen, dass für die größeren Zuordnungen Dirty 0 ist, was bedeutet, dass es genau dem entspricht, was sich auf der Festplatte befindet.
Sie können es erneut ausführen. pmap -XX
Abhängig von der ausgeführten Kernel-Version wird angezeigt, dass die erste Zuordnung einen Wert Shared_Clean
von 176 hat, der genau mit dem übereinstimmt, der für die Ausgabe von -XX je nach Kernel-Version unterschiedlich ist RSS
. Shared
Speicher bedeutet, dass die physischen Seiten von mehreren Prozessen gemeinsam genutzt werden. Da sie mit dem RSS-Code übereinstimmen, bedeutet dies, dass die gesamte im Speicher befindliche Bibliothek gemeinsam genutzt wird (siehe auch unten für weitere Erläuterungen zu Shared vs. Private):
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
Siehe auch
-fPIC
Nutzung hat sich vor einiger Zeit komplett geändert)?