Werden Dateien von Prozessen geöffnet, die in den Arbeitsspeicher geladen wurden?

24

Befehle sind zum Beispiel sedProgramme und Programme sind codierte Logik innerhalb einer Datei und diese Dateien befinden sich irgendwo auf der Festplatte. Wenn jedoch Befehle ausgeführt werden, wird eine Kopie ihrer Dateien von der Festplatte in den RAM gestellt , wo sie zum Leben erweckt werden und Dinge tun können und als Prozesse bezeichnet werden .

Prozesse können andere Dateien verwenden, darin lesen oder schreiben. In diesem Fall werden diese Dateien als offene Dateien bezeichnet. Es gibt einen Befehl , um alle geöffneten Dateien durch alle laufenden Prozesse zur Liste: lsof.

OK, ich frage mich also, ob die doppelte Lebensdauer eines Befehls, einer auf der Festplatte, der andere im RAM, auch für andere Arten von Dateien gilt, zum Beispiel für Dateien, für die keine Logik programmiert ist, die aber einfach Container sind Daten.

Ich gehe davon aus, dass auch von Prozessen geöffnete Dateien in den Arbeitsspeicher geladen werden. Ich weiß nicht, ob es wahr ist, es ist nur eine Intuition.

Könnte jemand einen Sinn daraus machen?

Hai
quelle

Antworten:

27

Bei der Ausführung von Befehlen wird jedoch eine Kopie der Dateien von der Festplatte in den Arbeitsspeicher verschoben.

Das ist (im Allgemeinen) falsch. Wenn ein Programm ausgeführt wird (durch Ausführen (2) ...), ändert der Prozess (der dieses Programm ausführt ) seinen virtuellen Adressraum und der Kernel konfiguriert die MMU für diesen Zweck neu. Lesen Sie auch über den virtuellen Speicher . Beachten Sie, dass Anwendungsprogramme ihren virtuellen Adressraum mithilfe von mmap (2) & munmap& mprotect (2) ändern können , das auch vom dynamischen Linker verwendet wird (siehe ld-linux (8) ). Siehe auch madvise (2) & posix_fadvise (2) & mlock (2) .

Zukünftige Seitenfehler werden vom Kernel verarbeitet, um (träge) Seiten aus der ausführbaren Datei zu laden. Lesen Sie auch über das Verprügeln .

Der Kernel verwaltet einen großen Seiten-Cache . Lesen Sie auch über Copy-on-Write . Siehe auch readahead (2) .

OK, ich frage mich also, ob die doppelte Lebensdauer eines Befehls, einer auf der Festplatte, der andere im RAM, auch für andere Arten von Dateien gilt, zum Beispiel für Dateien, für die keine Logik programmiert ist, die aber einfach Container sind Daten.

Für Systemaufrufe wie read (2) & write (2) wird auch der Seiten-Cache verwendet. Wenn sich die zu lesenden Daten darin befinden, wird keine Platten-E / A-Operation durchgeführt. Wenn Festplatten-E / A benötigt wird, werden die gelesenen Daten sehr wahrscheinlich in den Seiten-Cache gestellt. Wenn Sie also in der Praxis denselben Befehl zweimal ausführen, kann es vorkommen, dass beim zweiten Mal keine physischen E / A-Vorgänge auf der Festplatte ausgeführt werden (wenn Sie eine alte rotierende Festplatte - keine SSD - haben, hören Sie dies möglicherweise. oder beobachten Sie sorgfältig Ihre Festplatten-LED).

Ich empfehle, ein Buch wie Betriebssysteme zu lesen : Drei einfache Teile (frei herunterladbar, eine PDF-Datei pro Kapitel), in denen dies alles erklärt wird.

Siehe auch Linux Ate My RAM und führen Befehle wie xosview, top, htopoder cat /proc/self/mapsoder cat /proc/$$/maps(siehe proc (5) ).

PS. Ich konzentriere mich auf Linux, aber andere Betriebssysteme haben auch virtuellen Speicher und Seiten-Cache.

Basile Starynkevitch
quelle
35

Nein, eine Datei wird beim Öffnen nicht automatisch in den Speicher eingelesen. Das wäre schrecklich ineffizient. sedLiest beispielsweise wie viele andere Unix-Tools seine Eingabe zeilenweise. Es muss selten mehr als die aktuelle Zeile gespeichert werden.

Mit ist awkes das selbe. Es wird jeweils ein Datensatz gelesen , der standardmäßig eine Zeile ist. Wenn Sie Teile der Eingabedaten in Variablen speichern, ist das natürlich zusätzlich 1 .

Einige Leute haben die Angewohnheit, Dinge wie zu tun

for line in $(cat file); do ...; done

Da die Schal der erweitern müssen $(cat file)Befehlssubstitutions vollständig , bevor noch die erste Iteration des forLaufschleife, dies wird die gesamte liest filein den Speicher (in den von der Shell benutzten Speicher der auszuführende forSchleife). Das ist ein bisschen albern und auch unelegant. Stattdessen sollte man tun

while IFS= read -r line; do ...; done <file

Dies wird filezeilenweise verarbeitet (aber lesen Sie "IFS = read -r line" ).

Das zeilenweise Verarbeiten von Dateien in der Shell ist jedoch nur selten erforderlich, da die meisten Dienstprogramme ohnehin zeilenorientiert sind (siehe Warum wird eine Shell-Schleife zum Verarbeiten von Text verwendet, der als fehlerhaft angesehen wird? ).

Ich arbeite in der Bioinformatik und bei der Verarbeitung großer Mengen genomischer Daten wäre ich nicht in der Lage, viel zu tun, wenn ich nicht nur die Teile der Daten im Speicher belasse, die unbedingt erforderlich sind. Wenn ich beispielsweise die Datenbits entfernen muss, mit denen Personen aus einem 1-Terabyte-Datensatz mit DNA-Varianten in einer VCF-Datei identifiziert werden können (da diese Art von Daten nicht öffentlich zugänglich gemacht werden kann), gehe ich zeilenweise vor Bearbeitung mit einem einfachen awkProgramm (dies ist möglich, da das VCF-Format zeilenorientiert ist). Ich nicht lesen Sie die Datei in den Speicher, verarbeiten es dort, und schreiben Sie es wieder heraus! Wenn die Datei komprimiert wäre, würde ich sie durchlaufen lassen zcatoder gzip -d -c, da gzipStreaming-Verarbeitung von Daten, auch nicht die gesamte Datei in den Speicher lesen.

Selbst bei nicht zeilenorientierten Dateiformaten wie JSON oder XML gibt es Stream-Parser, mit denen große Dateien verarbeitet werden können, ohne dass alles im RAM gespeichert werden muss.

Bei ausführbaren Dateien ist dies etwas komplizierter, da gemeinsam genutzte Bibliotheken bei Bedarf geladen und / oder von Prozessen gemeinsam genutzt werden können (siehe z. B. Laden von gemeinsam genutzten Bibliotheken und RAM-Nutzung ).

Caching habe ich hier nicht erwähnt. Dies ist die Aktion, bei der RAM zum Speichern von Daten verwendet wird, auf die häufig zugegriffen wird. Kleinere Dateien (z. B. ausführbare Dateien) können vom Betriebssystem in der Hoffnung zwischengespeichert werden, dass der Benutzer viele Verweise auf sie erstellt. Abgesehen vom ersten Lesen der Datei werden nachfolgende Zugriffe auf den Arbeitsspeicher und nicht auf die Festplatte durchgeführt. Caching, wie das Puffern von Eingaben und Ausgaben, ist normalerweise für den Benutzer weitgehend transparent, und die Menge an Arbeitsspeicher, die zum Cachen von Dingen verwendet wird, kann sich in Abhängigkeit von der von Anwendungen usw. zugewiesenen RAM-Menge dynamisch ändern.


1 Technisch gesehen lesen die meisten Programme wahrscheinlich jeweils einen Teil der Eingabedaten, entweder explizit gepuffert oder implizit durch die Pufferung, die die Standard-E / A-Bibliotheken durchführen, und präsentieren diesen Teil dann zeilenweise im Code des Benutzers. Es ist viel effizienter, ein Vielfaches der Blockgröße der Festplatte zu lesen, als z. B. ein Zeichen gleichzeitig. Diese Blockgröße ist jedoch selten größer als eine Handvoll Kilobyte.

Kusalananda
quelle
Sie sagten, es ist möglich, gemeinsam genutzte Bibliotheken in den Arbeitsspeicher zu laden. Ist es auch möglich, eine reguläre Datei zu laden, die nur Daten in den Arbeitsspeicher enthält, auch wenn dies keinen Sinn ergibt?
Sharkant
1
@ sharkant Natürlich. Das ist nur eine Frage des Hinzufügens von Daten zu einer Variablen (oder einem Array oder einem Hash oder einer beliebigen Datenstruktur, die die betreffende Sprache liefert), bis die gesamte Datei gespeichert wurde. Mit awk, { a[i++] = $0 }würden alle Zeilen der Eingabedatei zum Array hinzufügen a. Möglicherweise möchten Sie auch die C-Funktion nachschlagen mmap(), aber ihre Verwendung ist hier möglicherweise etwas unangebracht.
Kusalananda
6
sed,, awkund andere zeilenorientierte Programme lesen keine Zeile gleichzeitig in den Speicher, da Nur-Text-Dateien keinen Zeilenindex enthalten und Dateisystem-APIs und Low-Level-Speicherhardware einen oder mehrere "Sektoren" lesen (normalerweise 512) oder 1024 Bytes) gleichzeitig. Es würde mich wundern, wenn das Betriebssystem weniger als 8 KB in den Speicher einliest, bevor die erste Zeile verarbeitet wurde.
Russell Borogove
5
Obwohl ein Hilfsprogramm wie sednur jeweils eine Zeile in den Speicher einliest, ist es erwähnenswert, dass das Betriebssystem kostenlosen RAM zum Zwischenspeichern von Dateien verwendet, damit auf diese schnell zugegriffen werden kann. Wenn Sie mit sedeiner kleineren Datei arbeiten, kann es vorkommen, dass das Betriebssystem die gesamte Datei im Arbeitsspeicher zwischenspeichert und der Vorgang vollständig im RAM ausgeführt wird. Siehe: en.wikipedia.org/wiki/Page_cache
Sean Dawson
5
@sharkant Es ist sinnvoll, eine Datei vollständig im Arbeitsspeicher verfügbar zu haben (siehe die andere Antwort, mmap ist hier der Schlüsselwort-Systemaufruf). Beispielsweise möchte ein Datenbanksystem normalerweise, um den Zugriff zu vereinfachen und zu beschleunigen, die gesamte Datenbank oder zumindest einige der Indizes, die in den Speicher abgebildet werden. Dies bedeutet nicht unbedingt, dass sich das Ganze tatsächlich im Gedächtnis befindet. Dem Betriebssystem steht es frei, "vorzutäuschen", dass sich die Datei im Speicher befindet. Es teilt der Anwendung mit, dass "hier in diesem Speicherbereich Ihre Datei ist" und dass die Daten erst dann tatsächlich gelesen werden, wenn ein Lesevorgang durchgeführt wurde (genau wie nach dem Auslagern des Prozesses).
Jonas Schäfer
5

Nein. Obwohl es heutzutage fantastisch ist, RAM zu haben, gab es eine Zeit, in der RAM eine sehr begrenzte Ressource war (ich habe gelernt, auf einer VAX 11/750 mit 2 MB RAM zu programmieren) und das einzige, was im RAM aktiv war, waren ausführbare Dateien und Datenseiten von aktiven Prozessen und Dateidaten, die sich im Puffercache befanden.
Der Puffercache wurde geleert und die Datenseiten wurden ausgelagert. Und häufig zuweilen. Die schreibgeschützten ausführbaren Seiten wurden überschrieben und Seitentabellen markiert. Wenn das Programm diese Seiten erneut berührte, wurden sie aus dem Dateisystem ausgelagert. Die Daten wurden aus dem Swap ausgelagert. Wie oben erwähnt, hat die STDIO-Bibliothek Daten in Blöcken abgerufen und sie wurden vom Programm nach Bedarf abgerufen: fgetc, fgets, fread usw. Mit mmap kann eine Datei in den Adressraum eines Prozesses abgebildet werden, wie dies beispielsweise mit erfolgt ist Shared Library Objekte oder auch normale Dateien. Ja, Sie können ein gewisses Maß an Kontrolle haben, ob es sich im RAM befindet oder nicht (mlock), aber es geht nur so weit (siehe den Fehlercode-Abschnitt von mlock).

Roger L.
quelle
1
Die Aussage "Ihr RAM wird zu klein für Ihre Dateien" ist jetzt wahr, wie es in den alten Tagen von VAX war.
Federico Poloni
1
@Federico_Poloni Heute nicht ganz so wahr. Bei meinem letzten Arbeitgeber hatten wir einen PC der Workstation-Klasse mit 1 TB RAM und nur 0,5 TB Festplatte. (Problemklasse: kleine Eingaben, mittlere Ausgaben, große Arrays mit wahlfreiem Zugriff während der Berechnung).
Nigel222