Linux Speichermanagement

Aus DebianforumWiki
Zur Navigation springen Zur Suche springen
Wiki ‹ Rund um den Kernel ‹ Linux Speichermanagement


Baustelle.png Baustelle: Dieser Artikel ist eine Baustelle. Das heißt, jemand hat sich dieses Artikels angenommen und überarbeitet ihn gerade.


LizenzOffen.png Lizenz: Dieser Artikel wurde als problematisch in Bezug auf der Lizenz markiert, dafür kann es verschiedene Gründe geben:
  • die Lizenz des Ursprünglichen Artikels ist unbekannt oder nicht kompatiblen mit der CC by SA
  • durch die Migration wurden der/die ursprüngliche(n) Autor(en) aus der History gelöscht
  • es wurden Inhalte ohne Zustimmung des ursprünglichen Autors übernommen
  • es gibt andere urheberrechtliche Bedenken gegen diesen Artikel.

Bitte hilf mit alle diese Fragen zunächst zu klären, danach kann dieser Hinweis entfernt werden.


Diskussion 62206

Einführung

Traditionelle Unixtools wie `top` zeigen bereits nach einer relativ kurzen Systemlaufzeit nur noch überraschend wenig freien Speicher an. Schon nach etwas surfen im Internet und einem Blick ins Postfach scheinen 512 MB Hauptspeicher voll gelaufen zu sein. Wo ist all der freie Speicher hin?

Der Löwenanteil wird für den "Disk Cache" verwendet und dieser "Festplattenpuffer" kann schnell mehrere hundert Megabyte belegen. Da ungenutzter Speicher bekanntlich verschwendeter Speicher ist, behält Linux einmal vorhandene Daten im Hauptspeicher, solange dieser nicht für laufende oder neu gestartete Programme benötigt wird.

Werden nun bereits zu einem früheren Zeitpunkt benötigte Daten erneut angefordert, so besteht eine gute Chance, dass sich diese noch immer im Cache befinden. Von dort lassen sie sich um ein Vielfaches schneller auslesen als von der Festplatte und selbst wenn die gewünschten Daten sich im Cache nicht mehr vorfinden und doch auf die Platte zugegriffen werden muss, verzeichnet man unterm Strich keinerlei Einbußen.

In diesem Zusammenhang belegter Speicher ist im Grunde genommen also freier Speicher, er wird lediglich einer sinnvollen Verwendung zugeführt, bis er anderweitig benötigt wird.

Die Ausgabe von free

Um eine bessere Einschätzung des tatsächlichen Speicherverbrauchs zu bekommen, hilft uns das Kommando `free -m`:

user@debian:~$ free -m
             total       used       free     shared    buffers     cached
Mem:           885        874         10          0         16        579
-/+ buffers/cache:        278        606
Swap:         1024          0       1024

Die Zeile mit -/+ buffers/cache zeigt an, wie viel Speicher aus Anwendungssicht frei beziehungsweise belegt ist. In diesem Beispiel belegen auf meinem System laufende Anwendungen 278 MB, während 606 MB frei zur Verfügung stehen.

Ein Blick auf die oberste Zeile zeigt nun, dass von den 885 MB, die auf meinem System für Daten und Anwendungen zur Verfügung stehen, insgesamt 874 MB benutzt werden. Dies ergibt sich aus den 278 MB für Anwendungen in Addition mit den 16 MB für "Buffers" und 579 MB für den "Cache". Ich kann also zufrieden sein, der Kernel lässt nur 10 MB tatsächlich brachliegen.

Die letzte Zeile schließlich gibt Auskunft über den Swapspeicher, also die Auslagerungsdatei. Meine 1024 MB sind vollkommen ungenutzt, das heißt mein Hauptspeicher ist während dieser Sitzung noch nie an seine Grenzen gestoßen und ein Auslagern von Daten auf die Festplatte war folglich bisher nicht notwendig. Wird während einer Sitzung vom Swapspeicher Gebrauch gemacht, so bleiben die ausgelagerten Daten bis zu einem Neustart erhalten, sie könnten ja zu einem späteren Zeitpunkt noch einmal benötigt werden.

Abschließend noch eine Bemerkung zum freien Speicher. Unter total wird free niemals die volle, im Rechner tatsächlich vorhandene Speichermenge ausgeben. Dies liegt hauptsächlich daran, dass der Kernel selbst nicht ausgelagert werden kann, von ihm belegter Speicher kann folglich auch niemals freigegeben werden. Darüber hinaus gibt es je nach Systemarchitektur möglicherweise Speicherbereiche, die hardwareseitig für andere Zwecke reserviert sind und somit auch vom verfügbaren Speicher abgezogen werden. So werden beispielsweise auf x86-Systemen die ersten 16MB des Hauptspeichers als ZONE_DMA zur Unterstützung DMA-fähiger ISA-Karten reserviert, da solche altehrwürdigen Karten nur auf diesen Speicherbereich zugreifen können. Ein weiteres Beispiel für reservierten Speicher wären darüber hinaus sogenannte "Shared-Memory Grafikkarten", die keinen eigenen Speicher mitbringen und sich daher ein Stück des Hauptspeichers abzweigen müssen.

Das mysteriöse 880 MB Limit der x86er-Architektur

Grundsätzlich kann Linux nur auf Speicher zugreifen, der direkt in den Adressbereich des Kernels eingeblendet wurde. Standardmäßig läuft der Kernel im sogenannten "Low Memory" und kann auch nur dieses verwalten, was auf x86-Systemen zu oben benannter Beschränkung führt. Soll der Kernel Speicher über diesen Bereich hinaus verwalten, man spricht hierbei von sogenanntem "High Memory", so muss dieser zunächst in den virtuellen Adressbereich eingeblendet werden.

Auf x86-Systemen gibt es folgende Speicherbereiche:

ZONE_DMA	die ersten 16 MiB
ZONE_NORMAL	16MiB - 896MiB
ZONE_HIGHMEM	896 MiB - End

(Quelle: [the Linux Virtual Memory Manager], 8,4 MB)

Um also bei einem Hauptspeicher von 1 GB oder mehr den vollen Speicher nutzen zu können, muss "High Memory Support" im Kernel aktiviert sein:

root@debian:~# make menuconfig
Linux Kernel Configuration: Large amounts of memory

Processor Type and Features ---->
High Memory Support ----> 
(*) 4GB

Den "High Memory Support" zu aktivieren bremst Speicherzugriffe zumindest theoretisch ein wenig aus. Inwieweit sich dies praktisch bemerkbar macht, wird durchaus kontrovers diskutiert. Wie obigem Beispiel zu entnehmen ist, habe ich 1 GB Hauptspeicher, verzichte aber auf die zusätzlichen 128 MB zugunsten optimaler Performance. In meinem Fall ist dies kein großer Verlust, da mein Speicherbedarf selten auch nur in die Nähe der im schnellen "Low Memory" verfügbaren 880 MB gerät.

Seit Kernel 2.6.16 bietet Linux darüber hinaus die Möglichkeit, bis zu 1 GB Hauptspeicher als "Low Memory" zu adressieren, wobei allerdings möglicherweise Probleme mit proprietären Treibermodulen auftreten können:

root@debian:~# make menuconfig
 
Linux Kernel Configuration: Large amounts of memory

Processor Type and Features ---->
Memory split ---->
(*) 3G/1G user/kernel split (for full 1G low memory)

Der Unterschied zwischen Buffers und Cache

  • Buffers werden von vielen Prozessen belegt und beispielsweise als Eingangsqueues und ähnliches benutzt. Zumeist jedoch sind Buffers Ausgaben irgendeines Prozesses und Dateipuffer. Einfach ausgedrückt erlauben sie Prozessen Daten vorübergehend im Speicher zu halten, bis der Prozess Zeit findet diese zu verarbeiten.
  • Cache bedeutet typischerweise Festplattenpuffer und beinhaltet häufig vorkommende Plattenzugriffe. Wenn mehrere Prozesse auf die selben Dateien zugreifen, werden die meisten dieser Dateien im Cache zwischengespeichert und die Zugriffsgeschwindigkeit auf diese Weise deutlich erhöht.

Die Unterschiede zwischen VIRT, RES und SHR in top

  • `VIRT` steht für die virtuelle Größe eines Prozesses und ist die Summe seines aktuell belegten Speichers, von Speicher, den der Prozess in seinen Speicherbereich eingeblendet hat (beispielsweise Grafikkartenspeicher für den X-Server), von Dateien auf der Festplatte, die der Prozess eingeblendet hat (besonders "Shared Libraries") und von Speicher der mit anderen Prozessen geteilt wird. `VIRT` steht somit für die Speichermenge, auf die ein Programm momentan Zugriff hat.
  • `RES` steht für "Resident Size" und damit für genau die Menge an physichem Speicher, die momentan von einem Prozess belegt wird. Hieraus ergibt sich auch die im Bezug auf den verfügbaren Speicher angegebene prozentuale Speichernutzung in der %MEM-Spalte. Dieser Wert wird praktisch immer niedriger sein als der virtuelle Speicherverbrauch eines Prozesses (`VIRT`), da die meisten Programme zumindest von der C-Library abhängen.
  • `SHR` schließlich besagt, wie viel des virtuell belegten Speichers (`VIRT`) "shareable" ist, also mit anderen Prozessen geteilt werden kann. Benutzt ein Prozess beispielsweise eine bestimmte Library, so heißt dies nicht zwangsläufig, dass sich auch die gesamte Bibliothek tatsächlich im Speicher befindet. Verwendet der Prozess nur einige Funktionen der Bibliothek, so wird zwar die gesamte Bibliothek als Datei auf der Festplatte eingeblendet und sowohl unter `VIRT`, als auch unter `SHR` mitgerechnet, aber nur die Teile der Library, aus denen auch Funktionen benutzt werden, befinden sich wirklich im Speicher und zählen somit unter `RES`.

Der Speicherverbrauch einzelner Anwendungen

Die Ausgabe von ps

Zunächst beispielhaft die gekürzte Ausgabe von `ps aux` bezüglich `gedit` auf meinem Rechner mit Gnome 2.12:

user@debian:~$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1000      8005  6.5  1.5  23416 13740 ?        S    16:04   0:00 gedit

In diesem Zusammenhang sind vor allem die PID, die "virtual set size" VSZ und die "resident set size" RSS von besonderem Interesse. Der Ausgabe zufolge hat also `gedit` eine virtuelle Größe von etwa 23 MB und eine "Resident Size" von 13 MB.

Fälschlicherweise wird nun häufig entweder die eine oder die andere Ausgabe als Speicherverbrauch des betrefenden Programms unter Linux interpretiert. Tatsächlich sagt `ps` jedoch nichts über den "wirklichen" Speicherverbrauch einer Anwendung aus. Vielmehr wird sozusagen angezeigt, wieviel Speicher die Anwendung benötigen würde, wäre sie der einzige auf dem System ablaufende Prozess. Die Ursache für diese Diskrepanz liegt in den "Shared Libraries" begründet, also Bibliotheken deren Funktionen von vielerlei Programmen eingebunden werden.

Diese "Shared Libraries" werden nur ein einziges Mal in den Speicher geladen, ganz gleich ob ein einziger oder eine Vielzahl von Prozessen Teile dieser Bibliothek benötigen. Bei der Ausgabe von `ps` wird nun nicht näher zwischen dem eigentlichen Programmcode, Daten und eventuell benötigten Bibliotheken, auf die diese Anwendung zurückgreift, differenziert. Dies führt zu der Anzeige des enormen Seicherbedarfs von 13 MB oder gar 23 MB für einen einfachen Texteditor wie `gedit`.

Die Ausgabe von pmap

In obigem Beispiel läuft `gedit` unter der PID 8005. Gestatten wir uns nun einen differenzierteren Blick auf den Speicherverbrauch unter Zuhilfenahme von `pmap -d 8005`. Zur besseren Übersicht ist die Ausgabe erneut deutlich gekürzt.

user@debian:~$ pmap -d 8005
8005:   gedit
Address   Kbytes Mode  Offset           Device    Mapping
08048000     424 r-x-- 0000000000000000 003:00007 gedit
080b2000      12 rw--- 0000000000069000 003:00007 gedit
b6ace000      52 r---- 0000000000000000 003:00007 VeraMono.ttf
b6b3b000      68 r---- 0000000000000000 003:00007 Vera.ttf
b71a5000      80 r-x-- 0000000000000000 003:00007 libgnome-desktop-2.so.2.2.9
b71b9000       4 rw--- 0000000000013000 003:00007 libgnome-desktop-2.so.2.2.9
b71ba000      80 r-x-- 0000000000000000 003:00007 libgnome-menu.so.2.0.0
b71ce000       4 rw--- 0000000000013000 003:00007 libgnome-menu.so.2.0.0
b71cf000      40 r-x-- 0000000000000000 003:00007 libpangox-1.0.so.0.1003.1
b71d9000       4 rw--- 0000000000009000 003:00007 libpangox-1.0.so.0.1003.1
b71e2000    1208 r-x-- 0000000000000000 003:00007 libc-2.3.6.so
b7310000      20 r---- 000000000012e000 003:00007 libc-2.3.6.so
b7315000      12 rw--- 0000000000133000 003:00007 libc-2.3.6.so
b731a000      56 r-x-- 0000000000000000 003:00007 libpthread-2.3.6.so
b7328000       8 rw--- 000000000000d000 003:00007 libpthread-2.3.6.so
b7604000     504 r-x-- 0000000000000000 003:00007 libgdk-x11-2.0.so.0.800.12
b7682000      12 rw--- 000000000007e000 003:00007 libgdk-x11-2.0.so.0.800.12
b7685000    2976 r-x-- 0000000000000000 003:00007 libgtk-x11-2.0.so.0.800.12
b796d000      32 rw--- 00000000002e7000 003:00007 libgtk-x11-2.0.so.0.800.12
b797a000     144 r-x-- 0000000000000000 003:00007 libpangoft2-1.0.so.0.1003.1
b799e000       4 rw--- 0000000000024000 003:00007 libpangoft2-1.0.so.0.1003.1
b799f000      84 r-x-- 0000000000000000 003:00007 libart_lgpl_2.so.2.3.17
b79b4000       4 rw--- 0000000000014000 003:00007 libart_lgpl_2.so.2.3.17
b79c9000    1080 r-x-- 0000000000000000 003:00007 libxml2.so.2.6.23
b7ad7000      32 rw--- 000000000010e000 003:00007 libxml2.so.2.6.23
b7b0b000     388 r-x-- 0000000000000000 003:00007 libgnomeprint-2-2.so.0.1.0
b7b6c000       8 rw--- 0000000000061000 003:00007 libgnomeprint-2-2.so.0.1.0
b7b6f000     204 r-x-- 0000000000000000 003:00007 libgnomeprintui-2-2.so.0.1.0
b7ba2000       8 rw--- 0000000000032000 003:00007 libgnomeprintui-2-2.so.0.1.0
mapped: 23420K    writeable/private: 3212K    shared: 384K

Zunächst sticht ins Auge, dass jede "Shared Library" zweimal angeführt wird und zwar einmal für ihr Codesegment (Mode r-x--) und einmal für ihr Datensegment (Mode rw---). Unser besonderes Augenmerk gilt desweiteren dem Speicherverbrauch in KB, wie er in der zweiten Spalte angegeben ist. Überfliegt man diese einmal kurz, so wird schnell deutlich, dass der meiste Speicher von den Codesegmenten der Bibliotheken verbraucht wird, also jenem Teil, der für alle Anwendungen gleichzeitig zur Verfügung steht, die Funktionen der betreffenden Library benötigen.

Rechnet man diesen Anteil der "Shared Libraries" heraus, bekommt man als Ergebnis, was auch unter writeable/private in der letzten Zeile ausgegeben wird. So gesehen könnte man nun sagen, dass der "wahre" Speicherverbrauch von `gedit` in diesem Fall nur etwa 3 MB beträgt.

Wie viel Speicher ein bestimmter Prozess benötigt, liegt also stets im Auge des Betrachters. Begreift man die "Shared Libraries" als ohnehin vom System benötigte Bibliotheken, so wird man die Ausgabe von `pmap -d PID` unter writeable/private als den eigentlichen Speicherbedarf ansehen können. Wird eine dieser Bibliotheken dagegen exklusiv von einer bestimmten Anwendung benötigt, so wird man den zusätzlichen Speicherbedarf eher dieser zuordnen, was beispielsweise besonders bei der Benutzung einzelner Qt-Anwendungen unter Gnome oder umgekehrt einzelner GTK+-Anwendungen unter KDE ins Gewicht fällt.

Swappiness (2.6er-Kernels)

Die 2.6er-Kernelreihe beinhaltet die Möglichkeit zu beeinflussen, inwieweit Linux es vorzieht Prozesse und Daten auf die Festplatte auszulagern (Swapping), anstatt die Caches zu verkleinern, wenn der freie Speicher zur Neige geht.

Wenn eine Anwendung Speicher benötigt, der Speicher jedoch bereits vollkommen belegt ist, hat der Kernel zwei Möglichkeiten um Speicher freizuschaufeln und der Anwendung zur Verfügung zu stellen. Entweder kann Linux den "Disk Cache" im Speicher verkleinern, indem es vorrangig die ältesten Daten löscht, oder es kann weniger benutzte Teile von Programmen (Speicherseiten) auf die Swappartition auf der Festplatte auslagern. Es ist durchaus nicht einfach vorauszusagen, welche der beiden Methoden im Einzelfall die effizientere ist. Der Kernel fällt die Entscheidung, indem er anhand vorhergegangener Aktivitäten versucht die zu erwartende Effektivität der beiden Herangehensweisen grob abzuschätzen.

Vor Kernel 2.6 hatte der Benutzer keine Möglichkeiten, auf diese Berechnungen einzuwirken und es konnten sich Situationen ergeben, in denen der Kernel häufig die falsche Wahl traf und dadurch die Performance einbrach. Dank der Einführung der Swappiness in Kernel 2.6 kann in solchen Situationen nun Abhilfe geschaffen werden.

Die Swappiness kann Werte zwischen 0 und 100 annehmen um das Verhältnis zwischen dem Auslagern von Anwendungen und der Verkleinerung des Caches zu verändern. Bei 100 wird der Kernel stets bevorzugt nach inaktiven Anwendungen Ausschau halten und diese auslagern. Die Standardeinstellung für Swappiness ist 60. Ein Wert von 0 ergibt etwas in der Nähe des ursprünglichen Verhaltens, wobei Anwendungen die Speicher benötigten den Cache bis zu einem sehr kleinen Anteil am Gesamtspeicher schrumpfen konnten. Für Laptops, bei denen die Festplatte wünschenswerterweise in den Schlafmodus übergehen sollte, ist folglich ein Wert von 20 oder weniger empfehlenswert.

Die Swappiness kann bei laufendem System mit den folgenden Befehlen verändert werden:

user@debian:~$ sysctl -w vm.swappiness=30
user@debian:~$ echo 30 > /proc/sys/vm/swappiness

Anmerkung

Bei diesem Beitrag handelt es sich weitestgehend um eine Übersetzung des Artikels FAQ_Linux_Memory_Management aus dem Gentoo-Wiki. Da der Artikel dort unter der GNU Free Documentation License veröffentlicht wurde steht diese Abwandlung natürlich unter der selben Lizenz. Der Abschnitt "Der Speicherverbrauch einzelner Anwendungen" wurde maßgeblich durch einen exzellenten Blogeintrag auf virtualthreads.blogspot.com inspiriert. Aus Respekt vor den ursprünglichen Autoren und um deren Rechte nicht zu verletzen, bitte ich darum diesen Hinweis auch bei einer späteren Überarbeitung nicht zu entfernen.