Open Source im professionellen Einsatz

Speicheranforderungen im Proc-Filesystems analysieren

Spiegelbilder

Etwas Detailwissen darüber, wie Prozesse Speicher anfordern, hilft beim Debugging unwilliger oder übermäßig RAM-hungriger Prozesse. Obgleich es mehrere Formen zu unterscheiden gilt - alle Informationen spiegelt der Kernel augenblicklich ins Proc-Filesystem ein.

Der Linux-Kernel lässt über das Proc-Filesystem seiner Außenwelt eine Vielfalt an Informationen über alle Prozess zukommen. So spiegelt die Datei »/proc/ Prozessnummer/maps« die augenblickliche Gestalt des virtuellen Adressraums des betreffenden Prozesses wider, das so genannte Speicherbild oder die Memory Map[1]. Das Bild erlaubt es Programmierern und Systemadministratoren, die aktuellen Speicherbedürfnisse des Prozesses zu verstehen. Sogar Rückschlüsse auf Fehler, etwa nicht (mehr) zu befriedigende Speicheranforderungen, sind möglich. Mit gängigen Debugging-Werkzeugen ist solchen Problemen nicht so einfach beizukommen.

Um den Inhalt der Maps-Datei verständlich zu machen, beginnt der Artikel mit ein paar Grundlagen zum Kernel. Dann zeigt ein einfaches C-Programm, wie das Speichern eines Prozesses üblicherweise aussieht. Auf diesem Fundament aufbauend werden komplexere Speicheroperationen transparent: Anforderungen von Heap-Speicher, das Einblenden von Dateien in den virtuellen Adressraum und schließlich das Shared Memory.

Jeder bekommt seinen eigenen Speicher

Linux folgt dem Konzept des Virtual Memory: Jeder Prozess erhält seinen eigenen logischen Adressraum und nur für ihn erzeugen der Compiler und der Linker Adressen. Greift ein Prozesses auf einen Ort in seinem Adressraum zu, zum Beispiel auf eine Variable, setzen Betriebssystem und Prozessor den Aufruf auf deren tatsächliche physikalische Adresse um[1]. Wichtig: Ohne besonderes Zutun sind die Adressräume eines Prozesses nicht von anderen Prozessen aus zugänglich.

Linux teilt den virtuellen Adressraum eines Prozesses in einen für den User zugänglichen Teil und einen dem Kernel vorbehaltenen Bereich. Die Lage der Grenze zwischen beiden variiert unter anderem mit der eingesetzten Hardware-Plattform: Auf einer 32-Bit-Maschine liegt sie meist bei 3 GByte (hexadezimal: 0xC0000000, Makro PAGE_OFFSET im Kernel, [1]). Unterhalb liegt der User-, oberhalb der Kernel-Bereich.

Diese Einteilung pflanzt sich im User-Bereich fort: Der verfügbare Adressraum besteht aus einzelnen Virtual Memory Areas (VMAs). Jede VMA ist ein zusammenhängender Bereich von Adressen, die die gleiche Semantik besitzen. Code- und Daten-Segment eines Prozesses sind Beispiele für VMAs. Eine VMA ist durch folgende Attribute charakterisiert:

  • Ihre Start- und Endadresse. Deren Größe ist damit auch bestimmt. In der Praxis variieren die genauen Werte von Start- und Endadresse etwas mit der Kernelversion und der verwendeten Systembibliothek.
  • Ihre Rechte. Eine VMA, die Code enthält, besitzt die Rechte »r-xp«: Sie ist lesbar, nicht beschreibbar, aber ausführbar und nur für diesen Prozess sichtbar (privat).
  • Informationen über den so genannten Backing Store, den der Linux-Kernel auch unter dem Begriff »vm_file« führt. Sie spezifizieren, ob und wo die VMA ein Gegenstück auf dem Dateisystem besitzt. Dieses Pendant dient als Auffangbecken beim Auslagern der VMA aus dem Speicher. Bei den Code- und Daten-VMAs ist der Backing Store die Programm-Binary selbst.

Speicherbild visualisieren

Die Datei »/proc/ Prozessnummer/maps« listet die aktuellen VMAs. Über sie macht der Kernel einen Großteil der Informationen, die er über den virtuellen Adressraum des Prozesses hat, anderen Programmen und Usern zugänglich. Das bewusst einfach gehalten Testprogramm in Listing 1 nutzt dies aus.

Listing 1: Grundprogramm

01 #include <sys/types.h>
02 #include <sys/shm.h>
03 #include <sys/ipc.h>
04 #include <time.h>
05 #include <unistd.h>
06 #include <stdio.h>
07 #include <stdlib.h>
08 
09 int main() {
10 
11   /* return PID for checking */
12   printf("My Pid is: %dn", getpid());
13   fflush(stdout);
14 
15   sleep(30);
16 
17   return(0);
18 }

Der Prozess gibt nur seine eigene Prozess-ID (PID) aus und wartet dann 30 Sekunden, um dem Benutzer Gelegenheit zu geben, per »cat /proc/ Prozessnummer/maps« das Speicherbild in einem anderen Terminal auszugeben. Abbildung 1 zeigt das Ergebnis für einen Prozess mit der PID 5004.

Abbildung 1: Darstellung des Speicherbilds eines Prozesses in »/proc/Prozessnummer/maps«.

Abbildung 1: Darstellung des Speicherbilds eines Prozesses in »/proc/Prozessnummer/maps«.

Die ersten beiden Zeilen der Liste spiegeln das Code- beziehungsweise das Daten-Segment wider. Die erste Hexadezimalzahl in jeder Zeile (beispielsweise »08048000«) gibt den Beginn der VMA an, die nächste Zahl das Ende. Die folgende Zeichenkette enthält die erwähnten Attribute der VMA. Hier ist der Unterschied zwischen dem Code-Segment in der ersten und dem Daten-Segment in der zweiten Zeile zu sehen.

Die nächste Hex-Zahl gibt den Offset in der zugrunde liegenden Datei (Backing Store) an. Die Angabe »03:0a« liefert die Major- und die Minor-Nummer des Geräts, auf dem der Backing Store liegt. Auf dem System des Autors liefert »ls -la« im »/dev«-Verzeichnis unter anderem:

brw-rw----    1 root     disk       3,
  10 Mar 14  2003 /dev/hda10

Damit liegt der Backing Store, hier die Programmdatei, auf der Partition »/dev /hda10«. Die Inode-Nummer und der Name der Datei folgen.

Diesen Artikel als PDF kaufen

Als digitales Abo

Als PDF im Abo bestellen

comments powered by Disqus

Ausgabe 07/2013

Preis € 6,40

Insecurity Bulletin

Insecurity Bulletin

Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...

Linux-Magazin auf Facebook