Python-Unterprozess.Popen “OSError: [Errno 12] Speicher kann nicht zugeordnet werden”

114

Hinweis: Diese Frage wurde ursprünglich hier gestellt, aber die Kopfgeldzeit ist abgelaufen, obwohl keine akzeptable Antwort gefunden wurde. Ich stelle diese Frage erneut, einschließlich aller Details in der ursprünglichen Frage.

Ein Python-Skript führt alle 60 Sekunden eine Reihe von Klassenfunktionen mit dem Schedul- Modul aus:

# sc is a sched.scheduler instance
sc.enter(60, 1, self.doChecks, (sc, False))

Das Skript wird als daemonisierter Prozess ausgeführt, wobei der Code hier verwendet wird .

Eine Reihe von Klassenmethoden , die aufgerufen werden als Teil doChecks verwenden , um die subprocess Modul Systemfunktionen aufrufen , um System - Statistiken zu erhalten:

ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE).communicate()[0]

Dies läuft einige Zeit einwandfrei, bevor das gesamte Skript mit dem folgenden Fehler abstürzt:

File "/home/admin/sd-agent/checks.py", line 436, in getProcesses
File "/usr/lib/python2.4/subprocess.py", line 533, in __init__
File "/usr/lib/python2.4/subprocess.py", line 835, in _get_handles
OSError: [Errno 12] Cannot allocate memory

Die Ausgabe von free -m auf dem Server nach dem Absturz des Skripts lautet:

$ free -m
                  total       used       free     shared     buffers    cached
Mem:                894        345        549          0          0          0
-/+ buffers/cache:  345        549
Swap:                 0          0          0

Auf dem Server wird CentOS 5.3 ausgeführt. Ich kann weder auf meinen eigenen CentOS-Boxen noch mit anderen Benutzern reproduzieren, die das gleiche Problem melden.

Ich habe eine Reihe von Dingen versucht, um dies zu debuggen, wie in der ursprünglichen Frage vorgeschlagen:

  1. Protokollierung der Ausgabe von free -m vor und nach dem Popen-Aufruf. Die Speichernutzung ändert sich nicht wesentlich, dh der Speicher wird während der Ausführung des Skripts nicht allmählich aufgebraucht.

  2. Ich habe dem Popen-Aufruf close_fds = True hinzugefügt, aber das machte keinen Unterschied - das Skript stürzte immer noch mit demselben Fehler ab. Empfohlene hier und hier .

  3. Ich habe die Grenzwerte überprüft, die (-1, -1) sowohl bei RLIMIT_DATA als auch bei RLIMIT_AS zeigten, wie hier vorgeschlagen .

  4. Ein Artikel schlug der keinen Auslagerungsspeicher mit der Ursache sein , aber Swap ist auf Nachfrage tatsächlich zur Verfügung (nach der Web - Host) , und dies wurde auch vorgeschlagen , als ein falsche verursacht hier .

  5. Die Prozesse werden geschlossen, da dies das Verhalten der Verwendung von .communicate () ist, das durch den Python-Quellcode und die Kommentare hier gesichert wird .

Die gesamten Prüfungen finden Sie hier auf GitHub mit der in Zeile 442 definierten Funktion getProcesses. Dies wird von doChecks () ab Zeile 520 aufgerufen.

Das Skript wurde vor dem Absturz mit der folgenden Ausgabe ausgeführt:

recv(4, "Total Accesses: 516662\nTotal kBy"..., 234, 0) = 234
gettimeofday({1250893252, 887805}, NULL) = 0
write(3, "2009-08-21 17:20:52,887 - checks"..., 91) = 91
gettimeofday({1250893252, 888362}, NULL) = 0
write(3, "2009-08-21 17:20:52,888 - checks"..., 74) = 74
gettimeofday({1250893252, 888897}, NULL) = 0
write(3, "2009-08-21 17:20:52,888 - checks"..., 67) = 67
gettimeofday({1250893252, 889184}, NULL) = 0
write(3, "2009-08-21 17:20:52,889 - checks"..., 81) = 81
close(4)                                = 0
gettimeofday({1250893252, 889591}, NULL) = 0
write(3, "2009-08-21 17:20:52,889 - checks"..., 63) = 63
pipe([4, 5])                            = 0
pipe([6, 7])                            = 0
fcntl64(7, F_GETFD)                     = 0
fcntl64(7, F_SETFD, FD_CLOEXEC)         = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb7f12708) = -1 ENOMEM (Cannot allocate memory)
write(2, "Traceback (most recent call last"..., 35) = 35
open("/usr/bin/sd-agent/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/usr/bin/sd-agent/agent."..., 52) = 52
open("/home/admin/sd-agent/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/home/admin/sd-agent/dae"..., 60) = 60
open("/usr/bin/sd-agent/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/usr/bin/sd-agent/agent."..., 54) = 54
open("/usr/lib/python2.4/sched.py", O_RDONLY|O_LARGEFILE) = 8
write(2, "  File \"/usr/lib/python2.4/sched"..., 55) = 55
fstat64(8, {st_mode=S_IFREG|0644, st_size=4054, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7d28000
read(8, "\"\"\"A generally useful event sche"..., 4096) = 4054
write(2, "    ", 4)                     = 4
write(2, "void = action(*argument)\n", 25) = 25
close(8)                                = 0
munmap(0xb7d28000, 4096)                = 0
open("/usr/bin/sd-agent/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/usr/bin/sd-agent/checks"..., 60) = 60
open("/usr/bin/sd-agent/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/usr/bin/sd-agent/checks"..., 64) = 64
open("/usr/lib/python2.4/subprocess.py", O_RDONLY|O_LARGEFILE) = 8
write(2, "  File \"/usr/lib/python2.4/subpr"..., 65) = 65
fstat64(8, {st_mode=S_IFREG|0644, st_size=39931, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7d28000
read(8, "# subprocess - Subprocesses with"..., 4096) = 4096
read(8, "lso, the newlines attribute of t"..., 4096) = 4096
read(8, "code < 0:\n        print >>sys.st"..., 4096) = 4096
read(8, "alse does not exist on 2.2.0\ntry"..., 4096) = 4096
read(8, " p2cread\n        # c2pread    <-"..., 4096) = 4096
write(2, "    ", 4)                     = 4
write(2, "errread, errwrite)\n", 19)    = 19
close(8)                                = 0
munmap(0xb7d28000, 4096)                = 0
open("/usr/lib/python2.4/subprocess.py", O_RDONLY|O_LARGEFILE) = 8
write(2, "  File \"/usr/lib/python2.4/subpr"..., 71) = 71
fstat64(8, {st_mode=S_IFREG|0644, st_size=39931, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7d28000
read(8, "# subprocess - Subprocesses with"..., 4096) = 4096
read(8, "lso, the newlines attribute of t"..., 4096) = 4096
read(8, "code < 0:\n        print >>sys.st"..., 4096) = 4096
read(8, "alse does not exist on 2.2.0\ntry"..., 4096) = 4096
read(8, " p2cread\n        # c2pread    <-"..., 4096) = 4096
read(8, "table(self, handle):\n           "..., 4096) = 4096
read(8, "rrno using _sys_errlist (or siml"..., 4096) = 4096
read(8, " p2cwrite = None, None\n         "..., 4096) = 4096
write(2, "    ", 4)                     = 4
write(2, "self.pid = os.fork()\n", 21)  = 21
close(8)                                = 0
munmap(0xb7d28000, 4096)                = 0
write(2, "OSError", 7)                  = 7
write(2, ": ", 2)                       = 2
write(2, "[Errno 12] Cannot allocate memor"..., 33) = 33
write(2, "\n", 1)                       = 1
unlink("/var/run/sd-agent.pid")         = 0
close(3)                                = 0
munmap(0xb7e0d000, 4096)                = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x589978}, {0xb89a60, [], SA_RESTORER, 0x589978}, 8) = 0
brk(0xa022000)                          = 0xa022000
exit_group(1)                           = ?
Davidmytton
quelle
1
Auslaufen von 'Pipes' oder Filedescriptors oder einer damit verbundenen Kernel-Ressource?
Blauohr
Überprüfen /var/log/messagesoder dmesgBefehl.
Mark4o
Das Protokoll enthält nichts Relevantes.
Davidmytton
Haben Sie jemals eine Lösung dafür gefunden? Ich habe sehr ähnliche Symptome. Ich habe viel freien Speicher, aber nach dem Hinzufügen von Swap (wie einige Ihrer Antworten vermuten lassen) verschwindet das Problem. Ich habe mich nur gefragt, ob Sie in den Monaten zwischen damals und heute etwas herausgefunden haben. -- Vielen Dank!
dpb
Ich habe das gleiche Problem, aber keine Lösung - irgendwelche Ideen?

Antworten:

88

Als allgemeine Regel gilt (dh in Vanille-Kernel), fork/ cloneAusfälle mit ENOMEM speziell auftreten , weil entweder eine ehrliche Gott out-of-memory Bedingung ( dup_mm, dup_task_struct, alloc_pid, mpol_dup, mm_initusw. quaken), oder weil security_vm_enough_memory_mmSie es versäumt , während der Durchsetzung der overcommit Politik .

Überprüfen Sie zunächst die vmsize des Prozesses, bei dem der Verzweigungsversuch zum Zeitpunkt des Verzweigungsversuchs fehlgeschlagen ist, und vergleichen Sie dann die Menge an freiem Speicher (physisch und Swap) in Bezug auf die Überbindungsrichtlinie (geben Sie die Zahlen ein).

Beachten Sie in Ihrem speziellen Fall, dass Virtuozzo zusätzliche Kontrollen bei der Durchsetzung von Überbindungen durchführt . Darüber hinaus bin ich mir nicht sicher, wie viel Kontrolle Sie wirklich innerhalb Ihres Containers über die Swap- und Overcommit-Konfiguration haben (um das Ergebnis der Durchsetzung zu beeinflussen).

Um tatsächlich vorwärts zu kommen, würde ich sagen, dass Sie zwei Möglichkeiten haben :

  • zu einer größeren Instanz wechseln oder
  • setzt einigen Codierungsaufwand in effektiver Ihre Skripts Speichersteuer Fußabdruck

HINWEIS : Der Codierungsaufwand ist möglicherweise umsonst, wenn sich herausstellt, dass Sie es nicht sind, sondern ein anderer Typ, der in einer anderen Instanz auf demselben Server wie amock ausgeführt wurde.

Speicher-weise, wir wissen bereits , dass subprocess.PopenVerwendungen fork/ clone unter der Haube was bedeutet, dass jedes Mal , wenn Sie es nennen Sie anfordernden einmal mehr so viel Speicher wie Python bereits frisst , das heißt in den Hunderten von zusätzlichen MB, alle um dann execeine mickrige 10kB ausführbare Datei wie freeoder ps. Im Falle einer ungünstigen Überbindungsrichtlinie werden Sie bald sehen ENOMEM.

Alternativen dazu forkhaben nicht diese übergeordneten Seitentabellen etc. Kopierprobleme sind vforkund posix_spawn. Aber wenn Sie nicht das Gefühl , wie Stücke von Umschreiben subprocess.Popenin Bezug auf vfork/ posix_spawn, prüft , mit suprocess.Popennur einmal, am Anfang des Skripts (wenn Pythons Speicherbedarf ist minimal), um einen Shell - Skript zu erzeugen , dass dann läuft free/ ps/ sleepund was sonst noch in einem Schleife parallel zu Ihrem Skript; Fragen Sie die Ausgabe des Skripts ab oder lesen Sie sie synchron, möglicherweise aus einem separaten Thread, wenn Sie andere Dinge asynchron erledigen müssen. Führen Sie die Datenverarbeitung in Python durch, überlassen Sie das Forking jedoch dem untergeordneten Prozess.

JEDOCH , in Ihrem speziellen Fall können Sie überspringen aufrufen psund freezusammen; Diese Informationen stehen Ihnen in Python direkt zur Verfügungprocfs , unabhängig davon , ob Sie selbst oder über vorhandene Bibliotheken und / oder Pakete darauf zugreifen . Wenn psund freewaren die einzigen Dienstprogramme, die Sie ausgeführt haben, können Sie diese subprocess.Popenvollständig abschaffen .

Was auch immer Sie tun subprocess.Popen, wenn Ihr Skript Speicher verliert, werden Sie schließlich immer noch an die Wand stoßen. Behalten Sie es im Auge und überprüfen Sie es auf Speicherlecks .

vladr
quelle
7
Ich fand, dass das Ausführen gc.collect()kurz zuvor subprocess.Popenin den Fällen hilft, in denen der Garbage Collector eine Weile nicht ausgeführt wurde.
Letmaik
Ich habe einen Deamon geschrieben, um die Helfer-Skript-Strategie zu handhaben: github.com/SeanHayes/errand-boy Ich verwende sie in der Produktion mit einem meiner Kunden, und unsere Probleme "Speicher kann nicht zugeordnet werden" sind verschwunden.
Seán Hayes
Ich würde mich über eine einfache Diagnose /proc/fd/maps
freuen
18

Wenn free -mich mir die Ausgabe anschaue, scheint mir, dass Sie tatsächlich keinen Swap-Speicher zur Verfügung haben. Ich bin nicht sicher, ob unter Linux der Swap bei Bedarf immer automatisch verfügbar ist, aber ich hatte das gleiche Problem und keine der Antworten hier hat mir wirklich geholfen. Das Hinzufügen von Swap-Speicher hat das Problem in meinem Fall jedoch behoben. Da dies anderen Personen helfen könnte, die mit demselben Problem konfrontiert sind, poste ich meine Antwort zum Hinzufügen eines 1-GB-Swaps (unter Ubuntu 12.04, sollte dies jedoch für andere Distributionen ähnlich funktionieren).

Sie können zunächst überprüfen, ob ein Swap-Speicher aktiviert ist.

$sudo swapon -s

Wenn es leer ist, bedeutet dies, dass kein Swap aktiviert ist. So fügen Sie einen 1-GB-Swap hinzu:

$sudo dd if=/dev/zero of=/swapfile bs=1024 count=1024k
$sudo mkswap /swapfile
$sudo swapon /swapfile

Fügen Sie die folgende Zeile hinzu fstab, um den Swap dauerhaft zu machen.

$sudo vim /etc/fstab

     /swapfile       none    swap    sw      0       0 

Quelle und weitere Informationen finden Sie hier .

Nima
quelle
1
Hat das das gleiche oder ein anderes Problem behoben?
Dima Tisnek
Dies hat es für mich bei CentOS 6.4 getan. Fehler beim Installieren von awstats, danke.
Ruslan Abuzant
Obwohl ich damit den Code ausführen konnte, wurde das Problem, das wahrscheinlich in einer von mir verwendeten Bibliothek liegt, nicht wirklich behoben.
Philmaweb
1
Du hast mein Problem behoben. Vielen Dank! +1
sscirrus
8

Swap ist möglicherweise nicht der zuvor vorgeschlagene rote Hering. Wie groß ist der fragliche Python-Prozess kurz vor dem ENOMEM?

Steuert unter Kernel 2.6, /proc/sys/vm/swappinesswie aggressiv sich der Kernel zum Tauschen dreht, und overcommit*legt fest, wie viel und wie genau der Kernel den Speicher mit einem Augenzwinkern und einem Nicken aufteilen kann. Wie Ihr Facebook-Beziehungsstatus ist es kompliziert .

... aber Swap ist tatsächlich auf Anfrage verfügbar (laut Webhost) ...

Dies entspricht jedoch nicht der Ausgabe Ihres free(1)Befehls, der keinen von Ihrer Serverinstanz erkannten Swap Space anzeigt. Nun, Ihr Webhost weiß sicherlich viel mehr als ich über dieses Thema, aber virtuelle RHEL / CentOS-Systeme, die ich verwendet habe, haben gemeldet, dass der Austausch für das Gastbetriebssystem verfügbar ist.

Anpassen von Red Hat KB Artikel 15252 :

Ein Red Hat Enterprise Linux 5-System läuft einwandfrei ohne Swap-Speicher, solange die Summe aus anonymem Speicher und gemeinsam genutztem System V-Speicher weniger als etwa 3/4 der RAM-Größe beträgt. .... Systeme mit 4 GB RAM oder weniger [es wird empfohlen] mindestens 2 GB Swap-Speicherplatz.

Vergleichen Sie Ihre /proc/sys/vmEinstellungen mit einer einfachen CentOS 5.3-Installation. Fügen Sie eine Auslagerungsdatei hinzu. Ratsche runter swappinessund schau, ob du noch länger lebst.

Pilger
quelle
Wie kann die Größe des Python-Prozesses am besten überprüft werden? ps?
Davidmytton
so etwas wie ps -o user,pid,vsz="Mem(Kb)" -o cmd $PYTHON_PIDoder top (1) sollte es tun.
Pilcrow
7

Für eine einfache Lösung könnten Sie

echo 1 > /proc/sys/vm/overcommit_memory

Wenn Sie sicher sind, dass Ihr System über genügend Speicher verfügt. Siehe Linux über Commit-Heuristik .

serv-inc
quelle
1
Ich danke dir sehr! So eine einfache Lösung, du hast meinen Tag gerettet)
igolkotek
5

Ich vermute weiterhin, dass Ihr Kunde / Benutzer ein Kernelmodul oder einen Treiber geladen hat, der den clone()Systemaufruf stört (möglicherweise eine obskure Sicherheitsverbesserung, etwas wie LIDS, aber dunkler?) Oder einige der Kerneldatenstrukturen auffüllt, die dies tun ist notwendig für die fork()/ clone()den Betrieb (Prozesstabelle, Seite Tabellen, Dateideskriptors Tabellen usw.).

Hier ist der relevante Teil der fork(2)Manpage:

FEHLER
       EAGAIN fork () kann nicht genügend Speicher zuweisen, um die Seitentabellen des übergeordneten Elements zu kopieren und eine Aufgabenstruktur für das zuzuweisen
              Kind.

       EAGAIN Es war nicht möglich, einen neuen Prozess zu erstellen, da das Ressourcenlimit RLIMIT_NPROC des Aufrufers festgestellt wurde. Zu
              Wenn dieser Grenzwert überschritten wird, muss der Prozess entweder über die Funktionen CAP_SYS_ADMIN oder CAP_SYS_RESOURCE verfügen.

       ENOMEM fork () konnte die erforderlichen Kernelstrukturen nicht zuordnen, da der Speicher knapp ist.

Ich schlage vor, dass der Benutzer dies nach dem Booten in einen allgemeinen Kernel und mit nur einem minimalen Satz geladener Module und Treiber versucht (mindestens erforderlich, um Ihre Anwendung / Ihr Skript auszuführen). Von dort aus können sie unter der Annahme, dass es in dieser Konfiguration funktioniert, eine binäre Suche zwischen dieser und der Konfiguration durchführen, bei der das Problem auftritt. Dies ist die Standard-Fehlerbehebung für Systemadministratoren 101.

Die relevante Zeile in Ihrem straceist:

clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb7f12708) = -1 ENOMEM (Cannot allocate memory)

... Ich weiß, dass andere über Swap und Speicherverfügbarkeit gesprochen haben (und ich würde empfehlen, dass Sie mindestens eine kleine Swap-Partition einrichten, ironischerweise auch, wenn sie sich auf einer RAM-Disk befindet ... die Codepfade durch den Linux-Kernel, wenn dies der Fall ist Sogar ein winziger Teil des verfügbaren Swaps wurde weitaus umfangreicher ausgeübt als diejenigen (Ausnahmebehandlungspfade), in denen kein Swap verfügbar ist.

Ich vermute jedoch, dass dies immer noch ein roter Hering ist.

Die Tatsache, dass free0 (ZERO) Speicher gemeldet wird, der vom Cache und den Puffern verwendet wird, ist sehr störend. Ich vermute, dass die freeAusgabe ... und möglicherweise Ihr Anwendungsproblem hier durch ein proprietäres Kernelmodul verursacht werden, das die Speicherzuordnung in irgendeiner Weise stört.

Laut den Manpages für fork () / clone () sollte der Systemaufruf fork () EAGAIN zurückgeben, wenn Ihr Aufruf eine Verletzung des Ressourcenlimits verursachen würde (RLIMIT_NPROC) ... es heißt jedoch nicht, ob EAGAIN zurückgegeben werden soll durch andere Verstöße gegen RLIMIT *. In jedem Fall kann dies zu einem -ENOMEM-Fehler führen, wenn Ihr Ziel / Host über seltsame Vormetric- oder andere Sicherheitseinstellungen verfügt (oder wenn Ihr Prozess unter einer seltsamen SELinux-Richtlinie ausgeführt wird).

Es ist ziemlich unwahrscheinlich, dass es sich um ein normales Linux / UNIX-Problem handelt. Dort ist etwas Ungewöhnliches los.

Jim Dennis
quelle
1
Der Server wird auf einer Media Template (dv) -Basis ausgeführt, die Virtuozzo für die Virtualisierung verwendet.
Davidmytton
Durchsuchen Sie die Virtuozzo-Message Boards und das Bug-Tracking-System und suchen Sie möglicherweise nach Upgrades für das Virtuozzo-Subsystem.
Jim Dennis
2

Haben Sie versucht, Folgendes zu verwenden:

(status,output) = commands.getstatusoutput("ps aux")

Ich dachte, das hätte genau das gleiche Problem für mich behoben. Aber dann wurde mein Prozess getötet, anstatt nicht zu spawnen, was noch schlimmer ist.

Nach einigen Tests stellte ich fest, dass dies nur bei älteren Python-Versionen auftrat: Es passiert mit 2.6.5, aber nicht mit 2.7.2

Meine Suche hatte mich hierher geführt python-close_fds-problem , aber das Deaktivieren von closed_fds hatte das Problem nicht gelöst. Es ist immer noch eine Lektüre wert.

Ich fand heraus, dass Python Dateideskriptoren leckte, indem ich nur ein Auge darauf hatte:

watch "ls /proc/$PYTHONPID/fd | wc -l"

Wie Sie möchte ich die Ausgabe des Befehls erfassen und OOM-Fehler vermeiden ... aber es sieht so aus, als ob die einzige Möglichkeit für Benutzer darin besteht, eine weniger fehlerhafte Version von Python zu verwenden. Nicht ideal...

totaam
quelle
0

munmap (0xb7d28000, 4096) = 0
write (2, "OSError", 7) = 7

Ich habe schlampigen Code gesehen, der so aussieht:

serrno = errno;
some_Syscall(...)
if (serrno != errno)
/* sound alarm: CATROSTOPHIC ERROR !!! */

Sie sollten überprüfen, ob dies im Python-Code geschieht. Errno ist nur gültig, wenn der fortlaufende Systemaufruf fehlgeschlagen ist.

Bearbeitet, um hinzuzufügen:

Sie sagen nicht, wie lange dieser Prozess dauert. Mögliche Speicherkonsumenten

  • gegabelte Prozesse
  • nicht verwendete Datenstrukturen
  • gemeinsam genutzte Bibliotheken
  • Speicherzugeordnete Dateien
codeDr
quelle
2
Ja, aber wir sehen aus der Strace des OP, dass der erste Syscall-Fehler - von clone () - ENOMEM ist, wie berichtet wird. Dieser Fehler bleibt während des Low-Memory-Stolperns von Python durch die Traceback-Konstruktion erhalten, obwohl die C-Bibliothek errnoauf dem Weg viele Male zurückgesetzt wird.
Pilcrow