Sottoprocesso Python. Errori di apertura con OSError: [Errno 12] Impossibile allocare memoria dopo un periodo di tempo



Answers

Forse hai una perdita di memoria limitata da un limite di risorse ( RLIMIT_DATA , RLIMIT_AS ?) Ereditato dal tuo script python. Controlla il tuo * ulimit (1) * s prima di eseguire il tuo script e profila l'uso della memoria dello script, come altri hanno suggerito.

Cosa fai con la variabile ps dopo il frammento di codice che ci mostri? Tieni un riferimento ad esso, non essere mai liberato? Citando i documenti del modulo subprocess :

Nota: i dati letti sono memorizzati in memoria, quindi non utilizzare questo metodo se la dimensione dei dati è ampia o illimitata.

... e ps aux può essere prolisso su un sistema occupato ...

Aggiornare

Puoi controllare i rlimits con il tuo script python usando il modulo delle risorse :

import resource
print resource.getrlimit(resource.RLIMIT_DATA) # => (soft_lim, hard_lim)
print resource.getrlimit(resource.RLIMIT_AS)

Se questi ritornano "illimitati" - (-1, -1) - allora la mia ipotesi non è corretta e puoi andare avanti!

Vedi anche resource.getrusage , esp. i campi ru_??rss , che possono aiutarti a utilizzare lo strumento per il consumo della memoria con lo script python, senza eseguire il bombardamento su un programma esterno.

Question

Nota : questa domanda è stata chiesta con un riepilogo di tutti i tentativi di debug qui .

Ho uno script Python in esecuzione come processo in background eseguito ogni 60 secondi. Parte di questo è una chiamata al sottoprocesso. Aprire per ottenere l'output di ps .

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

Dopo aver eseguito per alcuni giorni, la chiamata ha un errore con:

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

Tuttavia l'output di free sul server è:

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

Ho cercato il problema e ho trovato questo articolo che dice:

La soluzione è aggiungere più spazio di swap al tuo server. Quando il kernel avvia il modellatore o il processo di scoperta, in primo luogo garantisce che lo spazio disponibile sullo store di swap sia sufficiente, se necessario, nel nuovo processo.

Prendo atto che non è disponibile lo scambio dall'output gratuito di cui sopra. È probabile che questo sia il problema e / o quali altre soluzioni potrebbero esserci?

Aggiornamento 13 agosto 09 Il codice precedente viene chiamato ogni 60 secondi come parte di una serie di funzioni di monitoraggio. Il processo è demonizzato e il controllo è pianificato usando sched . Il codice specifico per la funzione di cui sopra è:

def getProcesses(self):
    self.checksLogger.debug('getProcesses: start')

    # Memory logging (case 27152)
    if self.agentConfig['debugMode'] and sys.platform == 'linux2':
        mem = subprocess.Popen(['free', '-m'], stdout=subprocess.PIPE).communicate()[0]
        self.checksLogger.debug('getProcesses: memory before Popen - ' + str(mem))

    # Get output from ps
    try:
        self.checksLogger.debug('getProcesses: attempting Popen')

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

    except Exception, e:
        import traceback
        self.checksLogger.error('getProcesses: exception = ' + traceback.format_exc())
        return False

    self.checksLogger.debug('getProcesses: Popen success, parsing')

    # Memory logging (case 27152)
    if self.agentConfig['debugMode'] and sys.platform == 'linux2':
        mem = subprocess.Popen(['free', '-m'], stdout=subprocess.PIPE).communicate()[0]
        self.checksLogger.debug('getProcesses: memory after Popen - ' + str(mem))

    # Split out each process
    processLines = ps.split('\n')

    del processLines[0] # Removes the headers
    processLines.pop() # Removes a trailing empty line

    processes = []

    self.checksLogger.debug('getProcesses: Popen success, parsing, looping')

    for line in processLines:
        line = line.split(None, 10)
        processes.append(line)

    self.checksLogger.debug('getProcesses: completed, returning')

    return processes

Questo fa parte di una classe più grande chiamata checks che viene inizializzata una volta all'avvio del daemon.

L'intera classe di controlli è disponibile all'indirizzo http://github.com/dmytton/sd-agent/blob/82f5ff9203e54d2adeee8cfed704d09e3f00e8eb/checks.py con la funzione getProcesses definita dalla riga 442. Questa operazione è chiamata da doChecks () che inizia alla riga 520.




Hai osservato il tuo processo nel tempo?

  • lsof
  • ps -aux | grep -i pname
  • superiore

Tutto dovrebbe dare informazioni interessanti. Penso che il processo stia legando le risorse che dovrebbero essere liberate. C'è una possibilità che stia legando gli handle delle risorse (blocchi di memoria, flussi, handle di file, thread o handle di processo)? stdin, stdout, stderr dalla "ps" generata. Maniglie di memoria, ... da molte piccole allocazioni incrementali. Sarei molto interessato a vedere i comandi sopra riportati per il tuo processo quando ha appena terminato il lancio e l'esecuzione per la prima volta e dopo 24 ore di "seduta" lancerà regolarmente il processo secondario.

Poiché muore dopo pochi giorni, è possibile eseguirlo solo per pochi cicli, quindi riavviarlo una volta al giorno come soluzione alternativa. Questo ti aiuterebbe nel frattempo.

Giacobbe




Se stai eseguendo un processo in background, è probabile che tu abbia reindirizzato i tuoi processi stdin / stdout / stderr.

In tal caso, aggiungi l'opzione "close_fds = True" alla tua chiamata Popen, che impedirà al processo figlio di ereditare l'output reindirizzato. Questo potrebbe essere il limite che stai incontrando.




Non penso che le circostanze riportate nell'articolo di Zenoss a cui sei collegato siano l'unica causa di questo messaggio, quindi non è ancora chiaro che lo spazio di swap sia sicuramente il problema. Ti suggerirei di registrare alcune informazioni in più anche in caso di chiamate riuscite, in modo che tu possa vedere lo stato della memoria libera ogni volta appena prima di effettuare la chiamata ps .

Un'altra cosa: se si specifica shell=True nella chiamata Popen, viene visualizzato un comportamento diverso?

Aggiornamento: se non memoria, il prossimo colpevole possibile è in effetti handle di file. Vorrei consigliare di eseguire il comando non riuscito sotto strace per vedere esattamente quali chiamate di sistema stanno fallendo.






Links