Kernel (de) Kernel (it) Books Shell Sed/awk RAM/swap P35

Linux RAM & Swap

Autor und Copyright: Dr. Thomas Hertweck
Version: 0.2; Stand: 21. Mai 2006

Zu diesem Dokument

Die neuste Version dieses Dokuments kann stets unter http://www.thomashertweck.de/linuxram.html gefunden werden.

Diese kurze Betrachtung von RAM und Swap unter Linux erhebt natürlich keinen Anspruch auf Vollständigkeit und es wird keine Gewähr für alle Angaben oder daraus entstehender Konsequenzen übernommen. Es handelt sich hier auch nur um generelle Überlegungen, die im Einzelfalle anzupassen sind. Ich hoffe aber, dieser Text wird der ein oder anderen Person trotzdem hilfreich sein.

Einleitung

Jeder, der sich ein klein wenig mit Linux beschäftigt hat, ist schon einmal über den Begriff Swap gestolpert. Swap ist eine Art Hintergrundspeicher auf einem Massenspeichergerät (üblicherweise die Festplatte), der zusammen mit dem physikalisch vorhandenen Speicher (RAM = Random Access Memory) den sog. virtuellen Speicher (VM = Virtual Memory) bildet. Je nach Bedarf kann der Linux-Kernel Speicherseiten auslagern, d.h. vom RAM in den Swap-Bereich verlagern. Immer wieder kommt es zu der Frage, wie groß nun eigentlich so ein Swap-Bereich sein soll. Bei einigen Kerneln der 2.4er Reihe (bis 2.4.9) musste der Swap-Bereich zwingend zwei Mal so groß sein wie RAM, aber das gilt bei aktuellen Kerneln nicht mehr. Trotz allem findet man nachwievor oft die Daumenregel: Swap = 2 * RAM. Jedoch mach es in manchen Fällen keinen Sinn, sehr viel Swap anzulegen. Man kann sich natürlich auf den Standpunkt stellen, dass es bei der Größe heutiger Festplatten keine Rolle spielt, ob man 300 MB, 1 GB oder 2 GB für einen Swap-Bereich abzwackt, wo ingesamt vielleicht 500 GB Speicherplatz auf einer S-ATA Platte vorhanden ist. Trotz allem hier nun ein paar Gedanken zu RAM und Swap, die ein wenig über diesen Standpunkt hinausgehen.

Sollte man bei genug RAM überhaupt Swap anlegen?

Hier ist die Antwort schlicht "ja", auch wenn es auf den ersten Blick unsinnig erscheint. Selbst bei genügend RAM kann eine (dann sicherlich verhältnismäßig kleine) Swap-Partition aber Vorteile bringen, da Speicherseiten, auf die lange nicht zugegriffen wurde, ausgelagert werden können. So kann der physikalische Speicher für bessere Dinge, z.B. als Cache, genutzt werden, was dem Gesamtsystem Vorteile bringen kann! Es ist also immer gut, einen gewissen Swap-Bereich zu haben - der Kernel kümmert sich automatisch um die Entscheidung des Swappens (soll nun gewisser Speicherbereich ausgelagert werden oder nicht?), normalerweise hat der Anwender mit dieser "Magie" nichts zu tun. Bei Kernel 2.6 lässt sie sich allerdings beeinflussen, siehe dazu den folgenden Abschnitt.

Lässt sich das Swap-Verhalten beeinflussen?

Wie oben erklärt, kann der Kernel Speicherseiten auslagern statt den Cache zu verkleinern, wenn ihm das von Vorteil erscheint. Der Kernel hat im Prinzip zwei Möglichkeiten, wenn der RAM momentan vollständig genutzt wird (used, shared, buffer, cache). Er kann den Cache verkleinern, indem er die ältesten Daten im Cache verwirft oder es können Speicherseiten, die nur selten angesprochen werden, in den Swap-Bereich ausgelagert werden. Es ist natürlich nicht so einfach, hier stets die richtige Entscheidung zu treffen. Der Kernel versucht schlicht anhand der Aktivitäten, die vor kurzem stattgefunden haben und momentan stattfinden, die Effizienz der beiden Methoden abzuwägen. Bei älteren Kerneln konnte man diesen Entscheidungsprozess nicht beeinflussen, was mitunter zu Performance-Problemen geführt hat, wenn der Kernel desöfteren mit seinen Entscheidungen daneben lag. Bei Kernel 2.6 hat sich das jedoch geändert: es gibt "swappiness" (/proc/sys/vm/swappiness). Der Standardwert für swappiness ist 60, im Prinzip kann swappiness Werte zwischen 0 und 100 annehmen. Man ahnt es schon, es hat etwas mit Prozenten zu tun und macht dem Kernel eine Vorgabe, welche Methode er bevorzugen soll. Bei einem Wert von 100 wird der Kernel stets das Auslagern von inaktiven Speicherseiten bevorzgen. Bei einem Wert von 0 wird der Kernel stets das Verkleinern des Caches bevorzugen. Letzteres entspricht ungefähr dem Verhalten von pre 2.6er Kerneln. Swappiness ist ein Hinweis für den Kernel, er hat allerdings das letzte Wort - in gewissen Situationen ist nur eine der aufgezeigten Methoden möglich. Falls ürigens Speicherseiten ausgelagert wurden in den Swap-Bereich und sich danach später die Speicherbelegung des Systems reduziert, so werden die ausgelagerten Seiten nicht automatisch zurück in den RAM geladen (das wäre ineffizient). Das geschieht wirklich erst, wenn auf die Speicherseiten zugegriffen werden soll. So kann es passieren, dass eigentlich RAM wirklich frei ist (free, also auch nicht als Cache genutzt wird), trotzdem aber auch Swap-Bereich in Gebrauch ist. Der Cache sollte allerdings den freien Speicher dann relativ schnell wieder füllen, zumindest wenn auf dem System ein paar Aktivitäten stattfinden. Mit einem einfachen echo-Befehl kann man als Superuser einen anderen Wert nach /proc/sys/vm/swappiness schreiben - wie üblich beim Tunen des Systems über das proc-Filesystem sollte man dabei aber sehr umsichtig vorgehen.

$> cat /proc/sys/vm/swappiness
60
$> su
Password:
#> echo 30 > /proc/sys/vm/swappiness
#> cat /proc/sys/vm/swappiness
30
#> exit

Wie groß soll die Swap-Partition sein?

Das kann man sich einfach überlegen, wenn man ein "worst case" Szenario macht - wenn ich all die Programme, die ich immer mal so brauche, gleichzeitig verwende, wie viel Speicher wird dann insgesamt maximal verwendet? Von diesem Wert zieht man den physikalisch vorhandenen Speicher (RAM) ab, und dann hat man eine ungefähre Größe für den benötigten Swap-Bereich. Sollte die ermittelte Größe weit über dem physikalisch vorhandenen Speicher liegen und/oder wird im normalen Betrieb momentan sehr viel geswappt, dann wäre das Aufrüsten des RAM sicher vorteilhaft. Natürlich sollte man zu der ermittelten Zahl noch ein wenig Spielraum geben (z.B. kann ein g++ beim Übersetzen von C++ Quellcode mal eben sehr viel Speicher brauchen), ebenfalls sollte man den oben angeführten ersten Punkt beachten (d.h. selbst wenn mit obigem "worst case" Szenario kein Swap-Bereich von Nöten wäre, da z.B. 2 GB RAM oder mehr vorhanden sind, so sollte man doch einen dann kleinen Swap-Bereich anlegen), dann hat man für gängige (Heim-)Systeme eine gute Regel.

Swap ist sehr langsame im Vergleich zu anderen "Speichern" - am Schnellsten ist das CPU Register, dann kommen die Level 1 und 2 (und evtl. 3) Caches, dagegen ist der normale RAM dann schon sehr langsam, und Swap, naja, Swap ist quasi aus der Sicht der CPU gesehen ein Stillstand... Wenn also viel geswappt wird im Regelbetrieb, dann bremst das gewaltig, insofern ist Swap eben eher eine Speicher-Notlösung, um etwas machen zu können, was viel virtuellen Speicher braucht, aber es sollte nicht die Regel sein.

Es gibt Systeme, bei denen sollte man von o.a. Faustregel abweichen, auf das soll hier aber nicht näher eingegangen werden. Die entsprechenden Administratoren sollten hoffentlich wissen, was sie tun :-)

Was ist, wenn man nun doch einmal mehr virtuellen Speicher braucht?

Es kann natürlich vorkommen, dass in Einzelfällen mehr VM gebraucht wird (RAM + Swap) als nach obiger Faustregel zur Verfügung steht. Das heißt aber nicht, dass man deswegen von vorne herein seine Swap-Partition für diesen Ausnahmefall utopisch groß dimensionieren muss. In diesem Falle hilft einfach eine Swap-Datei weiter, die ebenfalls zur Auslagerung benutzt werden kann. War bei Kernel 2.4 eine Swap-Datei nochmals deutlich langsamer als eine Swap-Partition, so ist bei Kernel 2.6 eine Swap-Datei quasi fast gleich schnell. Damit kann man in diesen Einzelfällen also ganz gut leben. Zum Anlegen einer Swap-Datei generiert man sich mit dd eine Datei mit Nullen (Auslesen von /dev/zero) einer gewünschten Größe. Diese Datei wird dann mit Hilfe von mkswap in eine Swap-Datei umgewandelt, die wiederum mit swapon aktiviert werden kann. Hat man mehrere Swap-Bereiche unterschiedlicher Schnelligkeit, so sollte man gegebenenfalls geeignete Prioritäten für die jeweiligen Bereiche angeben. Nach erfolgreicher Aktivierung sollte der neue Swap-Bereich in der Ausgabe von "cat /proc/swaps" gelistet werden.

$> cat /proc/swaps
Filename    Type         Size    Used    Priority
/dev/hda6   partition    1052216 3300    -1
$> su
Password:
#> dd if=/dev/zero of=/swap.file bs=1M count=500
500+0 records in
500+0 records out
524288000 bytes (524 MB) copied, 18.6488 seconds, 28.1 MB/s
#> chmod 0600 /swap.file
#> mkswap /swap.file
Setting up swapspace version 1, size = 524283 kB
#> swapon -v /swap.file
swapon on /swap.file
#> cat /proc/swaps
Filename     Type         Size    Used    Priority
/dev/hda6    partition    1052216 3300    -1
/swap.file   file         511992  0       -2
#> exit

Wird keine Priorität explizit angegeben beim swapon-Befehl, so erhält der erste Swap-Bereich eine Standard-Priorität, der zweite Bereich eine etwas niedrigere Priorität, usw. Swap-Bereiche mit höherer Priorität werden beim Auslagern gegenüber Bereichen mit niedrigerer Priorität bevorzugt. Haben mehrere Bereiche gleiche Priorität, so erfolgt die Auslagerung im round-robin Verfahren. Laut Manual-Seite liegt die Priorität zwischen 0 und 32767. Bei SuSE-Systemen tauchen allerdings auch negative Prioritäten auf - eine Diskussion darüber fand auf der suse-linux (jetzt opensuse-de) Mailingliste statt und kann im Archiv der Liste nachgelesen werden.

Was ist mit Suspend-to-Disk?

Vorwiegend bei Laptops (aber natürlich geht es auch mit Desktop-PCs oder Servern) kommt ein Suspend-to-Disk in Frage, um den Rechner schlafen zu legen. Dazu werden die Speicherseiten auf der Swap-Partition auf der Festplatte abgelegt. Beim nächsten Booten wird der resume Parameter durch den Kernel ausgewertet und wird eine entsprechende Signatur in der Swap-Partition gefunden, so werden die Speicherseiten zurück in den RAM geladen und die Arbeit geht dort weiter, wo man vor dem Suspend-to-Disk aufgehört hat. Um dieses Feature zu nutzen, sollte die Swap-Partition auf der Festplatte also ausreichend groß sein, als Faustregel gilt hier ca. 30% größer als der physikalisch vorhandene Speicher.