GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Laden von Shared Libraries und RAM-Nutzung?

Ich frage mich, wie Linux gemeinsam genutzte Bibliotheken verwaltet. (Eigentlich spreche ich von Maemo Fremantle, einer Debian-basierten Distribution, die 2009 veröffentlicht wurde und auf 256 MB RAM läuft).

Nehmen wir an, wir haben zwei ausführbare Dateien, die auf libQtCore.so.4 verlinken und seine Symbole verwenden (unter Verwendung seiner Klassen und Funktionen). Nennen wir sie der Einfachheit halber a und b . Wir gehen davon aus, dass beide ausführbaren Dateien auf dieselben Bibliotheken verlinken.

Zuerst starten wir a . Die Bibliothek muss geladen werden. Wird es vollständig geladen oder wird es nur in dem erforderlichen Teil in den Speicher geladen (da wir nicht jede Klasse verwenden, wird nur der Code für die verwendeten Klassen geladen)?

Dann starten wir b . Wir nehmen an, dass a läuft noch. b verlinkt auch auf libQtCore.so.4 und verwendet einige der Klassen, die a verwendet, aber auch einige, die nicht von a verwendet werden . Wird die Bibliothek doppelt geladen (separat für a und separat für b )? Oder werden sie dasselbe Objekt bereits im RAM verwenden. Wenn b verwendet keine neuen Symbole und a wird bereits ausgeführt, wird der von gemeinsam genutzten Bibliotheken verwendete RAM zunehmen? (Oder wird der Unterschied unbedeutend sein)

Akzeptierte Antwort:

HINWEIS:Ich gehe davon aus, dass Ihr Gerät über eine Memory Mapping Unit (MMU) verfügt. Es gibt eine Linux-Version (µClinux), die keine MMU benötigt, und diese Antwort trifft dort nicht zu.

Was ist eine MMU? Es ist Hardware – Teil des Prozessors und/oder Speichercontrollers. Um das Verknüpfen gemeinsam genutzter Bibliotheken zu verstehen, müssen Sie nicht genau verstehen, wie eine MMU funktioniert, sondern nur, dass eine MMU einen Unterschied zwischen logisch zulässt Speicheradressen (die von Programmen verwendeten) und physische Speicheradressen (die tatsächlich auf dem Speicherbus vorhanden sind). Der Speicher wird in Seiten unterteilt, die unter Linux normalerweise 4 KB groß sind. Bei 4k-Seiten sind die logischen Adressen 0–4095 Seite 0, die logischen Adressen 4096–8191 Seite 1 usw. Die MMU ordnet diese physischen RAM-Seiten 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 geteilt: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 Bereich hat. Adresse 4096 in Prozess 1000 kann (und ist es normalerweise auch) völlig anders sein als Adresse 4096 in Prozess 1001.

Fast immer, wenn Sie eine Adresse sehen, handelt es sich um eine logische Adresse. User-Space-Programme beschäftigen sich kaum mit physikalischen Adressen.

Jetzt gibt es auch mehrere Möglichkeiten, Bibliotheken zu erstellen. Nehmen wir an, ein Programm ruft die Funktion foo() auf in der Bücherei. Die CPU weiß nichts über Symbole oder eigentliche Funktionsaufrufe – sie weiß nur, wie sie zu einer logischen Adresse springt und den dort gefundenen Code ausführt. Es gibt mehrere Möglichkeiten, dies zu tun (und ähnliche Dinge gelten, wenn eine Bibliothek auf ihre eigenen globalen Daten zugreift usw.):

  1. Es könnte eine logische Adresse hartcodiert werden, um es anzurufen. Dazu muss die Bibliothek immer an genau derselben logischen Adresse geladen werden. 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, daher muss im Grunde jede Bibliothek im System eindeutige logische Adressen haben. Es ist aber sehr schnell, wenn es funktioniert. (So ​​hat a.out die Dinge gemacht und die Art der Einrichtung, die das Prelinking macht, sozusagen).
  2. Es könnte eine gefälschte logische Adresse fest codieren und den dynamischen Linker anweisen, beim Laden der Bibliothek die richtige Adresse zu bearbeiten. Das kostet etwas Zeit beim Laden der Bibliotheken, aber danach geht es sehr schnell.
  3. Es könnte eine Indirektionsschicht hinzugefügt werden:Verwenden Sie ein CPU-Register, um die logische Adresse zu halten, an der die Bibliothek geladen wird, und greifen Sie dann als Offset von diesem Register auf alles zu. Dadurch entstehen bei jedem Zugriff Leistungseinbußen.
Verwandte:Linux – cp verliert die Metadaten der Datei?

So gut wie niemand verwendet #1 mehr, zumindest nicht auf Allzwecksystemen. Das Führen dieser eindeutigen logischen Adressliste ist auf 32-Bit-Systemen unmöglich (es gibt nicht genug davon) und auf 64-Bit-Systemen ein administrativer Alptraum. Die Vorverlinkung tut dies jedoch auf einer pro-System-Basis.

Ob #2 oder #3 verwendet wird, hängt davon ab, ob die Bibliothek mit GCCs -fPIC erstellt wurde (positionsunabhängiger Code) Option. #2 ist ohne, #3 ist mit. Im Allgemeinen werden Bibliotheken mit -fPIC erstellt , also passiert #3.

Weitere Einzelheiten finden Sie in Ulrich Dreppers How to Write Shared Libraries (PDF).

Endlich kann Ihre Frage beantwortet werden:

  1. Wenn die Bibliothek mit erstellt wurde -fPIC (wie es mit ziemlicher Sicherheit sein sollte), ist die überwiegende Mehrheit der Seiten für jeden Prozess, der sie lädt, genau gleich. Ihre Prozesse a und b kann die Bibliothek durchaus an verschiedenen logischen Adressen laden, aber diese zeigen auf dieselben physischen Seiten:Der Speicher wird gemeinsam genutzt. Außerdem stimmen die Daten im RAM genau mit denen auf der Festplatte überein, sodass sie nur dann geladen werden können, wenn sie vom Page Fault Handler benötigt werden.
  2. Wenn die Bibliothek ohne gebaut wird -fPIC , dann stellt sich heraus, dass die meisten Seiten der Bibliothek Linkbearbeitungen benötigen und anders sein werden. 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 dem überein, was sich auf der Festplatte befindet, daher wäre ich nicht überrascht, wenn die gesamte Bibliothek geladen wird. Es kann natürlich nachträglich auf Diskette (in der Auslagerungsdatei) ausgelagert werden.

Sie können dies mit dem pmap untersuchen Tool oder direkt durch Überprüfen verschiedener Dateien in /proc . Hier ist zum Beispiel eine (Teil-)Ausgabe von pmap -x auf zwei verschiedenen neu gespawnten bc s. Beachten Sie, dass die von pmap angezeigten Adressen wie üblich 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 wird, und pmap -x gibt Ihnen Details zu jedem separat. Sie werden feststellen, dass die logischen Adressen zwischen den beiden Prozessen unterschiedlich sind; 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 randomisiert.

An der Differenz zwischen Größe (KB) und residenter Größe (RSS) können Sie erkennen, dass nicht das gesamte Bibliothekssegment geladen wurde. Schließlich können Sie sehen, dass Dirty für die größeren Zuordnungen 0 ist, was bedeutet, dass es genau dem entspricht, was sich auf der Festplatte befindet.

Sie können es mit pmap -XX erneut ausführen , und es zeigt Ihnen – abhängig von der von Ihnen ausgeführten Kernelversion, da die Ausgabe von -XX je nach Kernelversion variiert –, dass die erste Zuordnung einen Shared_Clean hat von 176, was genau dem RSS entspricht . Shared Speicher bedeutet, dass die physischen Seiten von mehreren Prozessen gemeinsam genutzt werden, und da es mit dem RSS übereinstimmt, bedeutet dies, dass die gesamte Bibliothek, die sich im Speicher befindet, gemeinsam genutzt wird (siehe Siehe auch unten für weitere Erklärungen von gemeinsam genutzt vs. privat):

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

  • Informationen über die Speichernutzung eines Prozesses von /proc/pid/smaps erhalten, um eine Erklärung der ganzen clean/dirty shared/private-Sache zu erhalten.
Verwandte:Linux – Wie bekomme ich sar für den Vortag angezeigt?
Linux
  1. Messung der RAM-Nutzung eines Programms?

  2. „welches“ Äquivalent für gemeinsam genutzte Bibliotheken?

  3. Einführung in gemeinsam genutzte Linux-Bibliotheken (So erstellen Sie gemeinsam genutzte Bibliotheken)

  4. Strippen von gemeinsam genutzten Linux-Bibliotheken

  5. Wie bettet man Versionsinformationen in gemeinsam genutzte Bibliotheken und Binärdateien ein?

Jenkins Shared Library:Erstellen, Konfigurieren und Verwenden

Fehler beim Laden gemeinsam genutzter Bibliotheken libcrypto.so.1.1 – OpenSSL [Fix]

Steuern Sie die RAM- und CPU-Nutzung durch Kodi in Echtzeit

Konvertieren Sie eine statische Bibliothek in eine gemeinsam genutzte Bibliothek?

So initialisieren Sie eine gemeinsam genutzte Bibliothek unter Linux

Fehler beim Laden der gemeinsam genutzten Bibliothek (glew)