Python subprocess.Popen "OSError: [Errno 12] Cannot Allocate memory"


114

Nota: questa domanda è stata inizialmente posta qui, ma il tempo della taglia è scaduto anche se non è stata effettivamente trovata una risposta accettabile. Sto ripetendo questa domanda includendo tutti i dettagli forniti nella domanda originale.

Uno script python esegue una serie di funzioni di classe ogni 60 secondi utilizzando il modulo sched :

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

Lo script è in esecuzione come processo demonizzato utilizzando il codice qui .

Un certo numero di metodi di classe chiamati come parte di doChecks utilizzano il modulo subprocess per chiamare le funzioni di sistema al fine di ottenere statistiche di sistema:

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

Funziona correttamente per un periodo di tempo prima che l'intero script si blocchi con il seguente errore:

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

L'output di free -m sul server una volta che lo script è andato in crash è:

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

Il server esegue CentOS 5.3. Non sono in grado di riprodurre sulle mie scatole CentOS né con altri utenti che segnalano lo stesso problema.

Ho provato una serie di cose per eseguire il debug di questo come suggerito nella domanda originale:

  1. Registrazione dell'output di free -m prima e dopo la chiamata Popen. Non vi è alcun cambiamento significativo nell'utilizzo della memoria, ovvero la memoria non viene consumata gradualmente durante l'esecuzione dello script.

  2. Ho aggiunto close_fds = True alla chiamata Popen ma questo non ha fatto alcuna differenza: lo script si è comunque bloccato con lo stesso errore. Suggerito qui e qui .

  3. Ho controllato i limiti che mostravano (-1, -1) sia su RLIMIT_DATA che su RLIMIT_AS come suggerito qui .

  4. Un articolo ha suggerito che la mancanza di spazio di swap potrebbe essere la causa, ma lo swap è effettivamente disponibile su richiesta (secondo l'host web) e questo è stato suggerito anche come una causa fasulla qui .

  5. I processi vengono chiusi perché questo è il comportamento dell'uso di .communicate () come supportato dal codice sorgente Python e dai commenti qui .

Gli interi controlli possono essere trovati su GitHub qui con la funzione getProcesses definita dalla riga 442. Questa è chiamata da doChecks () a partire dalla riga 520.

Lo script è stato eseguito con strace con il seguente output prima del crash:

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)                           = ?

1
a corto di "pipe" o di descrittori di file o di una risorsa del kernel correlata a questi?
Blauohr

Controlla /var/log/messageso dmesgcomando.
mark4o

Non c'è niente nel registro rilevante per questo.
davidmytton

Hai mai trovato una soluzione a questo? Ho sintomi molto simili. Ho molta memoria di riserva, ma dopo aver aggiunto lo scambio (come suggeriscono alcune delle tue risposte), il problema scompare. Mi chiedevo solo se hai scoperto qualcosa nei mesi tra allora e adesso. -- Grazie!
dpb

Sto riscontrando lo stesso problema ma nessuna risoluzione: qualche idea?

Risposte:


88

Come regola generale (cioè in vanilla kernel), fork/ clonefallimenti con ENOMEM verificano in particolare a causa di uno un onesto a Dio out-of-memory condizioni ( dup_mm, dup_task_struct, alloc_pid, mpol_dup, mm_initecc croak), o perché security_vm_enough_memory_mmhai fallito , mentre far rispettare la politica di overcommit .

Inizia controllando la dimensione vms del processo che non è riuscito a eseguire il fork, al momento del tentativo di fork, quindi confrontalo con la quantità di memoria libera (fisica e di swap) in relazione alla politica di overcommit (inserisci i numeri).

Nel tuo caso particolare, nota che Virtuozzo ha controlli aggiuntivi nell'applicazione dell'overcommit . Inoltre, non sono sicuro di quanto controllo hai veramente, dall'interno del tuo contenitore, sulla configurazione di swap e overcommit (al fine di influenzare il risultato dell'applicazione).

Ora, per andare effettivamente avanti, direi che ti rimangono due opzioni :

  • passare a un'istanza più grande o
  • dedicare un po 'di lavoro alla programmazione per controllare in modo più efficace l' impronta di memoria dello script

NOTA che lo sforzo di codifica potrebbe essere del tutto inutile se si scopre che non sei tu, ma qualche altro ragazzo si è collocato in un'istanza diversa sullo stesso server mentre stai eseguendo amock.

Per quanto riguarda la memoria, sappiamo già che subprocess.Popenusa fork/ clone sotto il cofano , il che significa che ogni volta che lo chiami stai richiedendo ancora una volta tanta memoria quanta Python sta già consumando , cioè nelle centinaia di MB aggiuntivi, il tutto per poi execun piccolo eseguibile da 10kB comefree o ps. In caso di una politica di overcommit sfavorevole, vedrai presto ENOMEM.

Le alternative a forkquesto non hanno questo problema di copia delle tabelle della pagina principale ecc. Sono vforke posix_spawn. Ma se non hai voglia di riscrivere parti di subprocess.Popenin termini di vfork/ posix_spawn, considera di utilizzare suprocess.Popenuna sola volta, all'inizio del tuo script (quando l'impronta di memoria di Python è minima), per generare uno script di shell che poi esegue free/ ps/ sleepe qualsiasi altra cosa in un loop parallelo al tuo script; eseguire il polling dell'output dello script o leggerlo in modo sincrono, possibilmente da un thread separato se hai altre cose di cui occuparti in modo asincrono: fai il crunch dei dati in Python ma lascia il fork al processo subordinato.

TUTTAVIA , nel tuo caso particolare puoi saltare l'invocazione pse del freetutto; queste informazioni sono prontamente disponibili in Python direttamente daprocfs , sia che tu scelga di accedervi da solo o tramite librerie e / o pacchetti esistenti . Se pse freefossero le uniche utilità che stavi eseguendo, puoi farla finitasubprocess.Popen completamente .

Infine, qualunque cosa tu faccia per quanto ti subprocess.Popenriguarda, se il tuo script perde memoria, alla fine colpirai comunque il muro. Tienilo d'occhio e verifica la presenza di perdite di memoria .


7
Ho scoperto che l'esecuzione gc.collect()appena prima subprocess.Popenaiuta nei casi in cui il garbage collector non è stato eseguito per un po '.
letmaik

Ho scritto un demone per gestire la strategia di script di supporto: github.com/SeanHayes/errand-boy Lo sto usando in produzione con uno dei miei clienti e i nostri problemi "Impossibile allocare memoria" sono spariti.
Seán Hayes,

Apprezzerei una semplice diagnosi, ad esempio seguire /proc/fd/mapsper determinare se la memoria sovraccaricata è effettivamente il problema
Dima Tisnek

18

Guardando l'output free -mmi sembra che in realtà non sia disponibile memoria di swap. Non sono sicuro se in Linux lo scambio sarà sempre disponibile automaticamente su richiesta, ma stavo avendo lo stesso problema e nessuna delle risposte qui mi ha davvero aiutato. L'aggiunta di memoria di scambio, tuttavia, ha risolto il problema nel mio caso, quindi poiché ciò potrebbe aiutare altre persone ad affrontare lo stesso problema, pubblico la mia risposta su come aggiungere uno scambio da 1 GB (su Ubuntu 12.04 ma dovrebbe funzionare in modo simile per altre distribuzioni.)

Puoi prima controllare se c'è qualche memoria di swap abilitata.

$sudo swapon -s

se è vuoto, significa che non hai abilitato alcuno scambio. Per aggiungere uno scambio da 1 GB:

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

Aggiungere la seguente riga a fstabper rendere permanente lo scambio.

$sudo vim /etc/fstab

     /swapfile       none    swap    sw      0       0 

Fonte e ulteriori informazioni possono essere trovate qui .


1
Ha risolto lo stesso problema o qualche altro?
Dima Tisnek

Questo ha funzionato per me in CentOS 6.4. Ho riscontrato un errore durante l'installazione di awstats, grazie.
Ruslan Abuzant

Anche se questo mi ha permesso di eseguire il codice, non ha risolto il problema, che probabilmente risiede in una libreria che uso.
philmaweb

1
Hai risolto il mio problema. Grazie! +1
sscirrus

8

swap potrebbe non essere la falsa pista suggerita in precedenza. Quanto è grande il processo Python in questione appena prima del ENOMEM?

Sotto il kernel 2.6, /proc/sys/vm/swappinesscontrolla quanto aggressivamente il kernel si trasformerà in swap e overcommit*file quanto e con quale precisione il kernel può ripartire la memoria con un occhiolino e un cenno del capo. Come il tuo stato di relazione su Facebook, è complicato .

... ma lo scambio è effettivamente disponibile su richiesta (secondo l'host web) ...

ma non in base all'output del tuo free(1)comando, che non mostra lo spazio di swap riconosciuto dall'istanza del tuo server. Ora, il tuo host web potrebbe sicuramente sapere molto di più di me su questo argomento, ma i sistemi RHEL / CentOS virtuali che ho usato hanno segnalato lo scambio disponibile per il sistema operativo guest.

Adattamento dell'articolo 15252 della KB di Red Hat :

Un sistema Red Hat Enterprise Linux 5 funzionerà perfettamente senza alcuno spazio di swap fintanto che la somma della memoria anonima e della memoria condivisa del sistema V è inferiore a circa 3/4 della quantità di RAM. .... I sistemi con 4 GB di RAM o meno [si consiglia di avere] un minimo di 2 GB di spazio di swap.

Confronta le tue /proc/sys/vmimpostazioni con una semplice installazione di CentOS 5.3. Aggiungi un file di scambio. Abbassati swappinesse vedi se vivi ancora.


Qual è il modo migliore per controllare la dimensione del processo Python? ps?
davidmytton

qualcosa come ps -o user,pid,vsz="Mem(Kb)" -o cmd $PYTHON_PID, o top (1), dovrebbe farlo.
pilcrow


5

Continuo a sospettare che il tuo cliente / utente abbia qualche modulo del kernel o driver caricato che interferisce con la clone()chiamata di sistema (forse qualche oscuro miglioramento della sicurezza, qualcosa come LIDS ma più oscuro?) O che in qualche modo stia riempiendo alcune delle strutture dati del kernel che sono necessari per il funzionamento di fork()/ clone()(tabella dei processi, tabelle delle pagine, tabelle dei descrittori di file, ecc.).

Ecco la parte rilevante della fork(2)pagina man:

ERRORI
       EAGAIN fork () non può allocare memoria sufficiente per copiare le tabelle di pagina del padre e allocare una struttura di attività per
              bambino.

       EAGAIN Non è stato possibile creare un nuovo processo perché è stato rilevato il limite di risorse RLIMIT_NPROC del chiamante. Per
              superare questo limite, il processo deve avere la capacità CAP_SYS_ADMIN o CAP_SYS_RESOURCE.

       ENOMEM fork () non è riuscito ad allocare le strutture del kernel necessarie perché la memoria è scarsa.

Suggerisco di farlo provare all'utente dopo l'avvio in un kernel generico e di serie e con solo un set minimo di moduli e driver caricati (minimo necessario per eseguire l'applicazione / script). Da lì, supponendo che funzioni in quella configurazione, possono eseguire una ricerca binaria tra quella e la configurazione che presenta il problema. Questa è la risoluzione dei problemi 101 dell'amministratore di sistema standard.

La riga pertinente nel tuo straceè:

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

... so che altri hanno parlato di swap e disponibilità di memoria (e consiglierei di impostare almeno una piccola partizione di swap, ironia della sorte anche se è su un disco RAM ... i percorsi del codice attraverso il kernel Linux quando ha anche una piccola parte di swap disponibile è stata esercitata in modo molto più estensivo rispetto a quelli (percorsi di gestione delle eccezioni) in cui è disponibile zero swap.

Tuttavia ho il sospetto che questa sia ancora una falsa pista.

Il fatto che freestia segnalando 0 (ZERO) memoria in uso dalla cache e dai buffer è molto preoccupante. Sospetto che l' freeoutput ... e forse il problema con la tua applicazione qui, siano causati da qualche modulo del kernel proprietario che interferisce in qualche modo con l'allocazione della memoria.

Secondo le pagine man per fork () / clone (), la chiamata di sistema fork () dovrebbe restituire EAGAIN se la tua chiamata causasse una violazione del limite delle risorse (RLIMIT_NPROC) ... tuttavia, non dice se EAGAIN deve essere restituito da altre violazioni di RLIMIT *. In ogni caso, se il tuo target / host ha una sorta di bizzarro Vormetric o altre impostazioni di sicurezza (o anche se il tuo processo è in esecuzione con una strana politica SELinux), allora potrebbe causare questo errore -ENOMEM.

È piuttosto improbabile che sia un normale problema Linux / UNIX. Hai qualcosa di non standard in corso lì.


1
Il server è in esecuzione su una base Media Template (dv) che utilizza Virtuozzo per la virtualizzazione.
davidmytton

Prova a cercare nelle bacheche di Virtuozzo e nel sistema di tracciamento dei bug e, forse, a cercare aggiornamenti al sottosistema Virtuozzo stesso.
Jim Dennis

2

Hai provato a usare:

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

Pensavo che questo avesse risolto lo stesso identico problema per me. Ma poi il mio processo è finito per essere ucciso invece di non riuscire a deporre le uova, il che è anche peggio.

Dopo alcuni test ho scoperto che ciò si verificava solo su versioni precedenti di python: succede con 2.6.5 ma non con 2.7.2

La mia ricerca mi aveva portato qui python-close_fds-issue , ma la disattivazione di closed_fds non aveva risolto il problema. Vale comunque la pena leggerlo.

Ho scoperto che Python perdeva i descrittori di file semplicemente tenendolo d'occhio:

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

Come te, voglio catturare l'output del comando e voglio evitare errori OOM ... ma sembra che l'unico modo sia che le persone utilizzino una versione meno buggata di Python. Non ideale ...


0

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

Ho visto un codice sciatto che assomiglia a questo:

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

Dovresti controllare per vedere se questo è ciò che sta accadendo nel codice Python. Errno è valido solo se la chiamata di sistema in corso non è riuscita.

Modificato per aggiungere:

Non dici quanto dura questo processo. Possibili consumatori di memoria

  • processi biforcuti
  • strutture dati inutilizzate
  • biblioteche condivise
  • file mappati in memoria

2
Sì, ma vediamo dalla strace dell'OP che il primo errore di syscall - da clone () - è ENOMEM come riportato. Questo errore viene preservato durante l'inciampo di memoria insufficiente di Python attraverso la costruzione di traceback, anche se la libreria C errnoviene ripristinata molte volte lungo il percorso.
pilcrow

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.