Hinweis : Diese Frage wurde erneut mit einer Zusammenfassung aller Debugging-Versuche gestellt hier .
Ich habe ein Python-Skript, das alle 60 Sekunden als Hintergrundprozess ausgeführt wird. Ein Teil davon ist ein Aufruf von subprocess.Popen , um die Ausgabe von ps .
%Vor%Nach einigen Tagen läuft der Aufruf mit:
%Vor%Die Ausgabe von kostenlos auf dem Server lautet jedoch:
%Vor%Ich habe nach dem Problem gesucht und dieser Artikel , der sagt:
Lösung ist es, mehr Swap-Speicherplatz zu Ihrem Server hinzuzufügen. Wenn der Kernel versucht, den Modellierer- oder Erkennungsprozess zu starten, stellt er zunächst sicher, dass genügend Platz auf dem Tauschspeicher vorhanden ist, um den neuen Prozess bei Bedarf zu speichern.
Ich bemerke, dass es keinen verfügbaren Swap von der obigen freien Ausgabe gibt. Ist das wahrscheinlich das Problem und / oder welche anderen Lösungen gibt es?
Update 13.8.09 Der obige Code wird alle 60 Sekunden als Teil einer Reihe von Überwachungsfunktionen aufgerufen. Der Prozess ist daemonisiert und die Überprüfung wird mithilfe von geplant geplant. Der spezifische Code für die obige Funktion lautet:
%Vor%Dies ist Teil einer größeren Klasse namens checks, die einmalig beim Start des Daemon initialisiert wird.
Die gesamte Check-Klasse kann unter Ссылка mit der Funktion getProcesses gefunden werden Zeile 442. Dies wird von doChecks () ab Zeile 520 aufgerufen.
Wenn Sie popen verwenden, müssen Sie close_fds = True übergeben, wenn Sie zusätzliche Dateideskriptoren schließen möchten.
Das Erstellen einer neuen Pipe, die in der _get_handles-Funktion aus der Back-Trace erfolgt, erstellt zwei Dateideskriptoren, aber Ihr aktueller Code schließt sie nie und Sie treffen schließlich Ihr System max fd limit.
Nicht sicher, warum der Fehler, den Sie erhalten, eine nicht ausreichende Speicherbedingung anzeigt: Es sollte ein Dateibeschreibungsfehler sein, da der Rückgabewert von pipe()
einen Fehlercode für dieses Problem hat.
Sie haben vielleicht ein Speicherleck, das von einigen Ressourcenbeschränkungen begrenzt wird ( RLIMIT_DATA
, RLIMIT_AS
?) geerbt von Ihrem Python-Skript. Überprüfen Sie Ihre * ulimit (1) * s, bevor Sie Ihr Skript ausführen, und profilieren Sie die Speichernutzung des Skripts wie von anderen vorgeschlagen.
Was machen Sie mit der Variablen ps
nach dem Codeausschnitt, den Sie uns zeigen? Behalten Sie einen Hinweis darauf, niemals frei zu werden? Zitieren Sie die subprocess
-Dokumentation :
Hinweis: Die gelesenen Daten werden im Speicher zwischengespeichert. Verwenden Sie diese daher nicht Methode, wenn die Datengröße groß oder unbegrenzt ist.
... und ps aux können bei einem ausgelasteten System sehr ausführlich sein ...
Aktualisieren
Sie können rlimits mit Ihrem Python-Skript überprüfen, indem Sie das Modul verwenden:
%Vor% Wenn diese "unbegrenzt" zurückgeben - (-1, -1)
- dann ist meine Hypothese falsch und Sie können weitermachen!
Siehe auch resource.getrusage
, insb. Die Felder ru_??rss
, die Ihnen helfen können, die Speicherbelegung mit dem Python-Skript zu instrumentieren, ohne auf ein externes Programm zuzugreifen.
Diese Swap-Space-Antwort ist falsch. Historisch gesehen, wollten Unix-Systeme Swap-Space zur Verfügung stellen, aber sie funktionieren nicht mehr so (und Linux hat nie so funktioniert). Sie sind nicht einmal knapp davor, nicht mehr genügend Arbeitsspeicher zu haben. Das ist wahrscheinlich nicht das eigentliche Problem - Ihnen geht eine andere begrenzte Ressource aus.
Gegeben, wo der Fehler auftritt (_get_handles ruft os.pipe () auf, um Pipes für das Kind zu erstellen), das einzige wirkliche Problem, auf das Sie stoßen könnten, sind nicht genügend freie Dateideskriptoren. Ich würde stattdessen nach nicht abgeschlossenen Dateien suchen (lsof -p auf der PID des Prozesses, der den popen ausführt). Wenn Ihr Programm wirklich viele Dateien gleichzeitig geöffnet halten muss, dann erhöhen Sie das Benutzerlimit und / oder das Systemlimit für offene Dateideskriptoren.
Wenn Sie einen Hintergrundprozess ausführen, haben Sie wahrscheinlich Ihre Prozesse stdin / stdout / stderr umgeleitet.
Hängen Sie in diesem Fall die Option "close_fds = True" an Ihren Popen-Aufruf an, wodurch verhindert wird, dass der untergeordnete Prozess die umgeleitete Ausgabe erbt. Dies ist möglicherweise die Grenze, auf die Sie stoßen.
Sie möchten möglicherweise tatsächlich warten, bis alle diese PS-Prozesse abgeschlossen sind, bevor Sie den Swap-Space hinzufügen.
Es ist überhaupt nicht klar, was "Ausführen als Hintergrundprozess, der alle 60 Sekunden ausgeführt wird" bedeutet.
Aber Ihr Aufruf an subprocess.Popen ist das Forking eines neuen Prozesses jedes Mal.
Aktualisieren .
Ich würde vermuten, dass du all diese Prozesse irgendwie im Stich lässt oder in einem Zombie-Zustand gehst. Die communicate
Methode sollte jedoch die erzeugten Subprozesse bereinigen.
Haben Sie Ihren Prozess im Laufe der Zeit beobachtet?
Alle sollten interessante Informationen geben. Ich denke, dass der Prozess Ressourcen bindet, die freigesetzt werden sollten. Besteht die Möglichkeit, dass Ressourcen-Handles (Speicherblöcke, Streams, Datei-Handles, Thread- oder Prozess-Handles) gebunden werden? stdin, stdout, stderr aus dem erstellten "ps". Speicher behandelt, ... aus vielen kleinen Zuweisungen. Ich wäre sehr interessiert zu sehen, was die obigen Befehle für Ihren Prozess anzeigen, wenn er gerade erst gestartet und ausgeführt wurde und nach 24 Stunden "dort" den Unterprozess regelmäßig startet.
Da es nach einigen Tagen abbricht, können Sie es nur für einige wenige Schleifen ausführen und es dann einmal pro Tag als Workaround neu starten. Das würde dir in der Zwischenzeit helfen.
Jacob
Sie müssen
%Vor%Ressourcen freizugeben.
Hinweis: Dies funktioniert nicht unter Windows.
Ich glaube nicht, dass die Umstände, die in dem Zenoss-Artikel angegeben sind, der einzige Grund für diese Nachricht ist, also ist es noch nicht klar, dass Swap-Space definitiv das Problem ist. Ich rate Ihnen, noch mehr Informationen zu sammeln, selbst bei erfolgreichen Anrufen, so dass Sie jederzeit vor dem Aufruf von ps
den Status des freien Speichers sehen können.
Noch eine Sache - wenn Sie shell=True
im Popen-Aufruf angeben, sehen Sie ein anderes Verhalten?
Update: Wenn nicht Speicher, der nächste mögliche Täter ist in der Tat Dateigriffe. Ich würde empfehlen, den fehlgeschlagenen Befehl unter strace
auszuführen, um genau zu sehen, welche Systemaufrufe fehlschlagen.
Virtueller Speicher ist wichtig !!!
Ich habe das gleiche Problem vor dem Hinzufügen von Swap zu meinem Betriebssystem festgestellt. Die Formel für virtuellen Speicher lautet normalerweise: SwapSize + 50% * PhysicalMemorySize. Ich löse das schließlich, indem ich entweder mehr physischen Speicher hinzufüge oder eine Swap-Platte hinzufüge. close_fds wird in meinem Fall nicht funktionieren.