Ich stoße beim Entwickeln oft auf die Situation, in der ich eine Binärdatei ausführe, etwa a.out
im Hintergrund, da diese einen längeren Job erledigt. Währenddessen nehme ich Änderungen am C-Code vor, der erstellt a.out
und a.out
erneut kompiliert wurde. Bisher hatte ich damit keine Probleme. Der ausgeführte Prozess wird a.out
normal fortgesetzt, stürzt nie ab und führt immer den alten Code aus, von dem aus er ursprünglich gestartet wurde.
Es handelte sich jedoch a.out
um eine riesige Datei, die möglicherweise mit der Größe des Arbeitsspeichers vergleichbar ist. Was würde in diesem Fall passieren? Und sagen wir, es ist mit einer gemeinsam genutzten Objektdatei verknüpft. libblas.so
Was passiert, wenn ich es zur libblas.so
Laufzeit geändert habe ? Was würde passieren?
Meine Hauptfrage ist - hat das Betriebssystem gewährleistet , dass , wenn ich laufe a.out
, dann der ursprüngliche Code immer normal ausgeführt wird, gemäß der ursprünglichen binär, unabhängig von der Größe der binären oder .so
Dateien , die es Links zu, auch wenn diese .o
und .so
Dateien werden modfied während Laufzeit?
Ich weiß, dass es diese Fragen gibt, die ähnliche Probleme angehen : /programming/8506865/when-a-binary-file-runs-does-it-copy-its-entire-binary-data-into-memory -at-einmal Was passiert, wenn Sie ein Skript während der Ausführung bearbeiten? Wie ist es möglich, ein Live-Update durchzuführen, während ein Programm ausgeführt wird?
Das hat mir geholfen, ein bisschen mehr darüber zu verstehen, aber ich glaube nicht, dass sie genau fragen, was ich will, was eine allgemeine Regel für die Konsequenzen der Änderung einer Binärdatei während der Ausführung ist
if they are read-only copies of something already on disc (like an executable, or a shared object file), they just get de-allocated and are reloaded from their source
, also habe ich den Eindruck, dass wenn Ihre Binärdatei riesig ist, wenn ein Teil Ihrer Binärdatei aus dem RAM geht, aber dann wieder benötigt wird, sie "von der Quelle neu geladen" wird - also alle Änderungen in Die.(s)o
Datei wird während der Ausführung wiedergegeben. Aber natürlich kann ich falsch verstanden haben - weshalb ich diese spezifischere Frage stelleNo, it only loads the necessary pages into memory. This is demand paging.
ich tatsächlich den Eindruck hatte, dass das, wonach ich gefragt habe, nicht garantiert werden kann.Antworten:
Obwohl die Frage zum Stapelüberlauf zunächst ausreichend zu sein schien, verstehe ich aus Ihren Kommentaren, warum Sie möglicherweise noch Zweifel daran haben. Für mich ist dies genau die Art von kritischer Situation , in der die beiden UNIX-Subsysteme (Prozesse und Dateien) kommunizieren.
Wie Sie vielleicht wissen, werden UNIX-Systeme normalerweise in zwei Subsysteme unterteilt: das Dateisubsystem und das Prozesssubsystem. Sofern dies nicht durch einen Systemaufruf anders angegeben wird, sollte der Kernel diese beiden Subsysteme nicht miteinander interagieren lassen. Es gibt jedoch eine Ausnahme: das Laden einer ausführbaren Datei in die Textbereiche eines Prozesses . Natürlich kann man argumentieren, dass diese Operation auch durch einen Systemaufruf (
execve
) ausgelöst wird , aber dies ist normalerweise der einzige Fall, in dem das Prozesssubsystem eine implizite Anforderung an das Dateisubsystem sendet.Da das Prozesssubsystem natürlich keine Möglichkeit hat, Dateien zu verarbeiten (andernfalls wäre es sinnlos, das Ganze in zwei Teile zu teilen), muss es alles verwenden, was das Dateisubsystem für den Zugriff auf Dateien bereitstellt. Dies bedeutet auch, dass das Prozesssubsystem jeder Maßnahme unterzogen wird, die das Dateisubsystem hinsichtlich der Ausgabe / Löschung von Dateien ergreift. In diesem Punkt würde ich empfehlen, Gilles 'Antwort auf diese U & L-Frage zu lesen . Der Rest meiner Antwort basiert auf dieser allgemeineren von Gilles.
Das erste, was beachtet werden sollte, ist, dass auf Dateien intern nur über Inodes zugegriffen werden kann . Wenn dem Kernel ein Pfad zugewiesen wird, besteht sein erster Schritt darin, ihn in einen Inode zu übersetzen, der für alle anderen Operationen verwendet wird. Wenn ein Prozess eine ausführbare Datei in den Speicher lädt, erfolgt dies über den Inode, der vom Dateisubsystem nach der Übersetzung eines Pfads bereitgestellt wurde. Inodes können mehreren Pfaden (Links) zugeordnet sein, und Programme können nur Links löschen. Um eine Datei und ihren Inode zu löschen, muss userland alle vorhandenen Links zu diesem Inode entfernen und sicherstellen, dass sie vollständig nicht verwendet wird. Wenn diese Bedingungen erfüllt sind, löscht der Kernel die Datei automatisch von der Festplatte.
Wenn Sie sich den Teil zum Ersetzen ausführbarer Dateien in Gilles 'Antwort ansehen, werden Sie feststellen , dass der Kernel je nachdem, wie Sie die Datei bearbeiten / löschen , unterschiedlich reagiert / sich anpasst, immer über einen im Dateisubsystem implementierten Mechanismus.
ETXTBSY
). Keine Konsequenzen.mv
es sich um eine atomare Operation handelt. Dies erfordert wahrscheinlich die Verwendung desrename
Systemaufrufs. Da Prozesse im Kernelmodus nicht unterbrochen werden können, kann nichts diesen Vorgang stören, bis er abgeschlossen ist (erfolgreich oder nicht). Auch hier gibt es keine Änderung des Inodes der alten Datei: Es wird ein neuer erstellt, und bereits ausgeführte Prozesse wissen nichts davon, selbst wenn er mit einem der Links des alten Inodes verknüpft ist.Neukompilieren einer Datei : Wenn Sie verwenden
gcc
(und das Verhalten ist wahrscheinlich für viele andere Compiler ähnlich), verwenden Sie Strategie 2. Sie können dies sehen, indem Sie einenstrace
der Prozesse Ihres Compilers ausführen:stat
undlstat
, dass die Datei bereits vorhanden ist .a.out
, verbleiben Inode und Inhalt auf der Festplatte, solange sie von bereits ausgeführten Prozessen verwendet werden.a.out
. Dies ist eine brandneue Inode und brandneue Inhalte, die bereits laufende Prozesse nicht interessieren.Wenn es nun um gemeinsam genutzte Bibliotheken geht, gilt das gleiche Verhalten. Solange ein Bibliotheksobjekt von einem Prozess verwendet wird, wird es nicht von der Festplatte gelöscht, unabhängig davon, wie Sie seine Links ändern. Immer wenn etwas in den Speicher geladen werden muss, führt der Kernel dies über den Inode der Datei durch und ignoriert daher die Änderungen, die Sie an den Links vorgenommen haben (z. B. das Verknüpfen mit neuen Dateien).
quelle
df
ist es falsch, die Anzahl der freien Bytes auf der Festplatte zu ermitteln, da keine Inodes benötigt werden Wurden alle entfernten Dateisystem-Links berücksichtigt? Also sollte ich verwendendf -i
? (Dies ist nur eine technische Kuriosität, ich muss die genaue Festplattennutzung nicht wirklich kennen!)rm
odermv
sie als Inode zur Originaldatei nicht entfernt werden, bis alle Prozesse ihre Verknüpfung zu dieser Inode entfernen.df
enthalten) Informationen über den Inode erhalten. Alle neuen Informationen, die Sie finden, beziehen sich auf die neue Datei und den neuen Inode. Der Hauptpunkt hierbei ist, dass das Prozesssubsystem kein Interesse an diesem Problem hat, sodass die Begriffe der Speicherverwaltung (Anforderungs-Paging, Prozessaustausch, Seitenfehler usw.) völlig irrelevant sind. Dies ist ein Problem mit dem Dateisubsystem, das vom Dateisubsystem behoben wird. Das Prozess-Subsystem kümmert sich nicht darum, dafür ist es nicht da.df -i
: Dieses Tool ruft wahrscheinlich Informationen aus dem Superblock oder dem Cache des fs ab, was bedeutet, dass es möglicherweise den Inode der alten Binärdatei enthält (für die alle Links gelöscht wurden). Dies bedeutet jedoch nicht, dass neue Prozesse diese alten Daten verwenden können.Nach meinem Verständnis würde der Kernel aufgrund der Speicherzuordnung eines laufenden Prozesses keine Aktualisierung eines reservierten Teils der zugeordneten Datei zulassen. Ich denke, falls ein Prozess ausgeführt wird, ist die gesamte Datei reserviert, sodass die Aktualisierung, da Sie eine neue Version Ihrer Quelle kompiliert haben, tatsächlich zur Erstellung eines neuen Satzes von Inodes führt. Kurz gesagt, die älteren Versionen Ihrer ausführbaren Datei bleiben über Seitenfehlerereignisse auf der Festplatte verfügbar. Selbst wenn Sie eine große Datei aktualisieren, sollte diese weiterhin verfügbar sein und der Kernel sollte die unberührte Version so lange sehen, wie der Prozess ausgeführt wird. Die ursprünglichen Datei-Inodes sollten nicht wiederverwendet werden, solange der Prozess ausgeführt wird.
Dies muss natürlich bestätigt werden.
quelle
Dies ist beim Ersetzen einer JAR-Datei nicht immer der Fall. Jar-Ressourcen und einige Lader zur Laufzeitreflexionsklasse werden erst von der Festplatte gelesen, wenn das Programm die Informationen explizit anfordert.
Dies ist nur ein Problem, da ein JAR lediglich ein Archiv ist und keine einzelne ausführbare Datei, die dem Speicher zugeordnet wird. Dies ist etwas off-stopic, aber immer noch ein Ableger Ihrer Frage und etwas, mit dem ich mir in den Fuß geschossen habe.
Also für ausführbare Dateien: ja. Für JAR-Dateien: möglicherweise (abhängig von der Implementierung).
quelle