Frage von JamesOffice, 38

Anzahl Speicherseiten im physikalischen Speicher nach Erzeugung eines neuen Prozesses mit fork()?

hallo zusammen, ich würde gerne wissen wie viele Speicherseiten im physikalischen Speicher unmittelbar nach Erzeugung eines Prozesses unter Linux mit fork() für diesen Prozess belegt werden und aus welchem Segment des Virtuellen Speichers diese Seiten vermutlich stammen?! könnte mir jemand bitte das mal erklären? Herzlichen Dank!

Antwort
von TeeTier, 11

Das wird dich vielleicht überraschen, aber es sind erstmal theoretisch exakt Null! (siehe Einschränkung dazu weiter unten!) :)

Und zwar teilen sich Eltern- und Kindprozess sämtliche Speicherseiten, solange, bis einer von beiden schreibend darauf zugreift. Erst in diesem Moment, wird die fragliche Seite kopiert und fortan verwenden beide Prozesse unterschiedlichen Speicher.

Das geschieht aber transparent, und dein Programm wird davon nichts feststellen können. Speicheradressen bleiben ebenfalls unverändert, da sie ja virtuell sind.

Zum ersten Satz meiner Antwort noch eine kleine Korrektur für Erbsenzähler: Natürlich werden auf Anhieb einige wenige Seiten kopiert, da Prozesseigene Strukturen unbedingt lokal sein müssen. Dazu zählen Signalmasken, Stack, diverse Handles und Tabellen, usw. Das alles ist aber nicht viel, und dürfte im besten Fall in eine einzige Speicherseite passen (bei Linux standardmäßig 4096 Byte).

Wenn du z. B. einen Rechner mit 8GB RAM hast, und dein Prozess belegt 7GB davon, dann kannst du ihn Problemlos noch einige hundert mal forken, sofern keiner der Prozesse irgendetwas schreibt. (dazu zählen Variablenzuweisungen!) Wenn dann alle Kinder nur noch den Speicher lesen, bis sie _exit() aufrufen, und danach der Status mit wait() vom Parent abgeholt wird, gibt es für den Kernel keine Veranlassung, Speicherseiten zu duplizieren, und du kannst vermeindlich 100 Prozesse mit jeweils 7GB RAM Nutzung auf einer 8GB Maschine ausführen. :)

Ein ähnliches Phänomen tritt auf, wenn du malloc() aufrufst. Der Kernel reserviert zu diesem Zeitpunkt tatsächlich noch keinen Speicher dafür! Erst wenn du z. B. mittels buf[i] auf auf einen Speicherbereich zugreifst, wird die entsprechende Seite reserviert.

Wenn du mit ...

char *buf = malloc(1024 * 1024 * 1024)

... also ein ganzes Gigabyte reservierst, passiert erst mal gar nichts.

Erst wenn du ...

buf[0] = 'X';

schreibst, wird die erste Seite (also 4096 Byte) tatsächlich reserviert. Deshalb dauert der Zugriff auf das erste Element einer Seitengrenze (0, 4096, 8192, etc.) immer länger, als auf den restlichen Seitenbereich.

Und wenn du es dir z. B. bei Echtzeitsystemen nicht leisten kannst, dass dir irgendwann der Kernel dazwischen funkt, um vermeindlich bereits reservierten Speicherplatz tatsächlich zu reservieren, musst du den Speicher vorher irgendwie initialisieren. (Z. B. mit memset() oder mit einer Schleife)

Man kann all dieses Verhalten noch mit diversen Systemfunktionen beeinflussen, u. a. ob ein Speicherbereich vom Swapping ausgenommen werden soll. (Openssl macht das auch so für den Speicher, der Schlüssel enthält.)

Naja, das ist ein sehr komplexes Thema, und ich möchte darauf hinweisen, dass ich evtl. einige oben genannte Sachen falsch in Erinnerung habe. In diesem Falle bitte ich um einen korrigierenden Kommentar!

Ansonsten solltest du dir UNBEDINGT das Buch "The Linux Programming Interface" kaufen. Das ist ein 1600 Seiten starker Klopper in Kleinstschrift. Ich habe fast 3 Wochen am Stück fast von Morgens bis Abends daran gelesen. Ist sehr anstrengend, aber unglaublich lehrreich!

Danach wirst du z. B. "Beejs Guide to Network Programming" und die anderen "Beejs Guides" vom Niveau her mit Mickey-Mouse Heften gleichsetzen!

Allein die Kapitel über Dateien, Demons, IPC, usw. sind Gold Wert.

Das Buch ist mit 99€ krass teuer, aber bei DIESEM Umfang ist der Preis als geradezu "billig" anzusehen. Außerdem ist Druck, Bindung und Lektorat erstklassig, und es kommt vom besten Verlag der Welt. Hinter den Fachbüchern von "No Starch Press" kann sich "O'Reilly" oder "Addison Wesley" verstecken ... auch wenn die größtenteils sehr gute Werke publizieren ... aber in NP haben diese Verlage wohl ihren Meister gefunden. ;)

Zum Beispiel kann man mit diesem Wissen dann User-Space-Prozesse starten, die nicht mehr beendet werden können ... wohlgemerkt nicht mal mehr von Root selbst! Mir war vorher gar nicht klar, dass so etwas überhaupt möglich ist. (Mit anderen Worten: "sudo kill -9 $pid" zeigt keinerlei Wirkung!)

Ich will jetzt hier keine Werbung machen, aber wer unter Linux programmiert, der MUSS das hier gelesen haben:

https://www.nostarch.com/tlpi

Und da "über den Tellerrand schauen" immer eine gute Sache ist, beschäftige dich auch mal ein bisschen mit den gängigen BSDs. Bücher dazu findest du im oben angepriesenen Verlag. (Dann merkt man nämlich erst mal, dass BSD und Linux VÖLLIG unterschiedlich sind, und sich selbst so "einfache" Systemaufrufe wie fork() massiv unterscheiden und ihre Eigenheiten haben.)

Also dann ... noch viel Spaß!

Schönen Abend noch! ;)

PS: Um deine Frage zu beantworten, rufe sbrk() mit Argument 0 auf.

Für mehr Infos:

man 2 brk

Sei dir aber darüber im Klaren, dass das Ganze sehr low level und Systemspezifisch ist!

Kommentar von TeeTier ,

PPS: Aufgrund eines Bugs hier auf GF bekomme ich irgendwie manchmal nicht richtig den Fragetext angezeigt, sodass ich bis eben nur die Überschrift gelesen hatte.

Alle Prozesse (Eltern und Kinder) teilen sich das (read-only) Textsegment. Nur wenn du den Schreibschutz aufhebst (was z. B. der Java JIT Compiler macht), bekommt jeder Prozess sein eigenes Textsegment ... und auch nur dann, wenn einer der Prozesse Änderungen vornimmt (Stichwort JIT).

Kommentar von JamesOffice ,

Ich bin dir wirklich sehr dankbar das hat mir sehr gut geholfen und das habe ich in Wikipedia gefunden 

"The fork operation creates a separate address space for the child. The child process has an exact copy of all the memory segments of the parent process. In modern UNIX variants that follow the virtual memory model from SunOS-4.0, copy-on-write semantics are implemented and the physical memory need not be actually copied. Instead, virtual memory pages in both processes may refer to the same pages of physical memory until one of them writes to such a page: then it is copied. This optimization is important in the common case where fork is used in conjunction with exec to execute a new program: typically, the child process performs only a small set of actions before it ceases execution of its program in favour of the program to be started, and it requires very few, if any, of its parent'sdata structures."

Nun eine Frage zu deinem Komentar : "Alle Prozesse (Eltern und Kinder) teilen sich das (read-only) Textsegment. Nur wenn du den Schreibschutz aufhebst (was z. B. der Java JIT Compiler macht), bekommt jeder Prozess sein eigenes Textsegment"

Es ist mir nun klar das sich Eltern- und Kindprozess den selber Speicherseiten teilen, die sich auf den selben Seitenrahmen im Physikalischen Speicher beziehen, bis einer von beiden schreibend drauf zugreift, erst in diesem Moment, verwenden beide Prozesse unterschiedlichen Speicher. Kann ich davon ausgehen, dass nach dem Aufruf von execve() den Schreibschutz aufgehoben wird, da das Textsegment ausgetauscht wird? Wenn Nein, was passiert denn bei execve() aus Sicht der Speicherverwaltung?
Vielen Dank im Voraus!

Kommentar von TeeTier ,

Erst mal vorweg: Deine Fragen sind richtig gut. Aber leider kann ich dir keine genaue Antwort geben, da ich es ehrlich gesagt nicht weiß.

In den Manpages steht, dass bei exec(), das data-, text-, bss- und stack-Segment "ersetzt" wird.

Was man jetzt genau unter "ersetzt" verstehen darf, und wie genau der Vorgang von statten geht, darüber gibt es keine Infos.

Und ich habe jetzt auch leider keine Zeit mehr, mich näher mit dem Thema zu befassen, sorry.

Wie an anderer Stelle schon erwähnt, möchte ich dir nochmal das Buch "The Linux Programming Interface" ans Herz legen, und evtl. auch "The Design and Implementation of the FreeBSD Operating System". Letzteres Buch ist zwar BSD spezifisch, und es gibt große Unteschiede, aber vermutlich steht dort viel drin, was du wissen möchtest. Das gibt es kostenlos im PDF Format:

https://www.freebsd.org/doc/en/books/

Guck dir bei der Gelegenheit auch gleich noch die anderen Bücher im verlinkten Verzeichnis an!

Ich hoffe, das hilft dir weiter. Viel Erfolg! :)

Keine passende Antwort gefunden?

Fragen Sie die Community