Subproceso de Python.Popen "OSError: [Errno 12] No se puede asignar memoria"


114

Nota: Esta pregunta se hizo originalmente aquí, pero el tiempo de recompensa expiró aunque no se encontró una respuesta aceptable. Estoy volviendo a hacer esta pregunta, incluidos todos los detalles proporcionados en la pregunta original.

Un script de Python ejecuta un conjunto de funciones de clase cada 60 segundos usando el módulo sched :

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

El script se ejecuta como un proceso demonizado usando el código aquí .

Varios métodos de clase que se llaman como parte de doChecks usan el módulo de subproceso para llamar a funciones del sistema con el fin de obtener estadísticas del sistema:

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

Esto funciona bien durante un período de tiempo antes de que todo el script se bloquee con el siguiente error:

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

La salida de free -m en el servidor una vez que el script se ha bloqueado es:

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

El servidor está ejecutando CentOS 5.3. No puedo reproducir en mis propias cajas CentOS ni con ningún otro usuario que informe el mismo problema.

He intentado varias cosas para depurar esto como se sugiere en la pregunta original:

  1. Registrar la salida de free -m antes y después de la llamada de Popen. No hay ningún cambio significativo en el uso de la memoria, es decir, la memoria no se utiliza gradualmente a medida que se ejecuta el script.

  2. Agregué close_fds = True a la llamada de Popen, pero esto no hizo ninguna diferencia: el script aún se bloqueó con el mismo error. Sugerido aquí y aquí .

  3. Revisé los rlimits que mostraban (-1, -1) tanto en RLIMIT_DATA como en RLIMIT_AS como se sugiere aquí .

  4. Un artículo sugirió que no tener espacio de intercambio podría ser la causa, pero el intercambio está disponible bajo demanda (según el proveedor de alojamiento web) y esto también se sugirió como una causa falsa aquí. .

  5. Los procesos se están cerrando porque ese es el comportamiento de usar .communicate () respaldado por el código fuente de Python y los comentarios aquí .

Las comprobaciones completas se pueden encontrar en GitHub aquíTodas las con la función getProcesses definida en la línea 442. Esto es llamado por doChecks () comenzando en la línea 520.

El script se ejecutó con strace con el siguiente resultado antes del bloqueo:

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
¿Se está quedando sin 'tuberías' o descriptores de archivos o un recurso del núcleo relacionado con estos?
Blauohr

Verificar /var/log/messageso dmesgmandar.
mark4o

No hay nada en el registro relevante para esto.
Davidmytton

¿Alguna vez consiguió una solución a esto? Tengo síntomas muy similares. Tengo mucha memoria libre, pero después de agregar swap (como sugieren algunas de sus respuestas), el problema desaparece. Me preguntaba si descubrió algo en los meses transcurridos entre entonces y ahora. -- ¡Gracias!
dpb

Me estoy encontrando con el mismo problema pero sin resolución, ¿alguna idea?

Respuestas:


88

Como regla general (es decir, en los núcleos de vainilla), fork/ clonefracasos con ENOMEM ocurren específicamente ya sea por un honesto a Dios fuera del estado de memoria ( dup_mm, dup_task_struct, alloc_pid, mpol_dup, mm_initetc. graznido), o debido a security_vm_enough_memory_mmque fallaron mientras que la aplicación de la política de sobreasignación .

Comience verificando el vmsize del proceso que no se pudo bifurcar, en el momento del intento de bifurcación, y luego compárelo con la cantidad de memoria libre (física y de intercambio) en lo que respecta a la política de sobreasignación (ingrese los números).

En su caso particular, tenga en cuenta que Virtuozzo tiene comprobaciones adicionales en la aplicación de compromisos excesivos . Por otra parte, no estoy seguro de cuánto control tiene verdad, desde dentro de su contenedor, a lo largo de intercambio y configuración overcommit (con el fin de influir en el resultado de la aplicación.)

Ahora, para poder avanzar, diría que te quedan dos opciones :

  • cambiar a una instancia más grande, o
  • Ponga un poco de esfuerzo en la codificación para controlar de manera más efectiva la huella de memoria de su script

TENGA EN CUENTA que el esfuerzo de codificación puede ser en vano si resulta que no es usted, sino algún otro tipo ubicado en una instancia diferente en el mismo servidor que usted ejecuta amock.

En cuanto a la memoria, ya sabemos que subprocess.Popenusa fork/ clone under the hood , lo que significa que cada vez que lo llamas, estás solicitando una vez más tanta memoria como Python ya está consumiendo , es decir, en los cientos de MB adicionales, todo para luego execun ejecutable insignificante de 10kB como freeo ps. En el caso de una política de sobrecompromiso desfavorable, pronto veráENOMEM .

Alternativas a las forkque no tienen este problema de copia de tablas de página principal, etc. son vforky posix_spawn. Pero si no tiene ganas de reescribir fragmentos de subprocess.Popenen términos de vfork/ posix_spawn, considere usar suprocess.Popensolo una vez, al comienzo de su script (cuando la huella de memoria de Python es mínima), para generar un script de shell que luego se ejecuta free/ ps/ sleepy cualquier otra cosa en un lazo paralelo a su secuencia de comandos; sondee la salida del script o léalo de forma sincrónica, posiblemente desde un hilo separado si tiene otras cosas de las que ocuparse de forma asincrónica: procese sus datos en Python pero deje la bifurcación al proceso subordinado.

SIN EMBARGO , en su caso particular, puede omitir la invocación psy por freecompleto; esa información está disponible para usted en Python directamente desdeprocfs , ya sea que elija acceder a ella usted mismo oa través de bibliotecas y / o paquetes existentes . Si psy freefueran las únicas utilidades que estaba ejecutando, entonces puede eliminarlas por subprocess.Popencompleto .

Finalmente, hagas lo que hagas en lo que a ti subprocess.Popenrespecta, si tu secuencia de comandos pierde memoria, eventualmente acabarás golpeando la pared. Vigílelo y verifique que no haya pérdidas de memoria .


7
Descubrí que ejecutar gc.collect()justo antes subprocess.Popenayuda en los casos en que el recolector de basura no se ha ejecutado durante un tiempo.
letmaik

Escribí un demonio para manejar la estrategia del script auxiliar: github.com/SeanHayes/errand-boy Lo estoy usando en producción con uno de mis clientes y nuestros problemas de "No se puede asignar memoria" se han ido.
Seán Hayes

Apreciaría un diagnóstico simple, por ejemplo, seguir /proc/fd/mapspara determinar si la memoria comprometida en exceso es de hecho el problema
Dima Tisnek

18

Mirando la salida de free -m me parece que en realidad no tiene memoria de intercambio disponible. No estoy seguro de si en Linux el intercambio siempre estará disponible automáticamente a pedido, pero estaba teniendo el mismo problema y ninguna de las respuestas aquí realmente me ayudó. Sin embargo, al agregar algo de memoria de intercambio, se solucionó el problema en mi caso, por lo que, dado que esto podría ayudar a otras personas que enfrentan el mismo problema, publico mi respuesta sobre cómo agregar un intercambio de 1 GB (en Ubuntu 12.04, pero debería funcionar de manera similar para otras distribuciones).

Primero puede verificar si hay alguna memoria de intercambio habilitada.

$sudo swapon -s

si está vacío, significa que no tiene ningún intercambio habilitado. Para agregar un intercambio de 1GB:

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

Agregue la siguiente línea fstabpara que el intercambio sea permanente.

$sudo vim /etc/fstab

     /swapfile       none    swap    sw      0       0 

La fuente y más información se pueden encontrar aquí .


1
¿Eso solucionó el mismo problema o algún otro?
Dima Tisnek

Esto lo hizo por mí en CentOS 6.4. Se produjo un error al instalar awstats, gracias.
Ruslan Abuzant

Aunque esto me permitió ejecutar el Código, realmente no solucionó el problema, que probablemente se encuentre en una biblioteca que uso.
philmaweb

1
Arreglaste mi problema. ¡Gracias! +1
sscirrus

8

El intercambio puede no ser la pista falsa sugerida anteriormente. ¿Qué tan grande es el proceso de Python en cuestión justo antes delENOMEM ?

Bajo el kernel 2.6, /proc/sys/vm/swappinesscontrola qué tan agresivamente se convertirá el kernel para intercambiar y overcommit*archiva cuánto y con qué precisión el kernel puede distribuir memoria con un guiño y un asentimiento. Al igual que el estado de su relación en Facebook, es complicado .

... pero el intercambio está disponible bajo demanda (según el proveedor de alojamiento web) ...

pero no de acuerdo con la salida de su free(1)comando, que muestra ningún espacio de intercambio reconocido por su instancia de servidor. Ahora bien, es posible que su proveedor de alojamiento web sepa mucho más que yo sobre este tema, pero los sistemas virtuales RHEL / CentOS que he usado han informado que hay intercambio disponible para el sistema operativo invitado.

Adaptación del artículo 15252 de la base de conocimiento de Red Hat :

Un sistema Red Hat Enterprise Linux 5 funcionará bien sin ningún espacio de intercambio siempre que la suma de la memoria anónima y la memoria compartida del sistema V sea inferior a aproximadamente 3/4 de la cantidad de RAM. .... Los sistemas con 4GB de RAM o menos [se recomienda tener] un mínimo de 2GB de espacio de intercambio.

Compare su /proc/sys/vmconfiguración con una instalación simple de CentOS 5.3. Agrega un archivo de intercambio. Mueva el trinquete swappinessy vea si vive más.


¿Cuál es la mejor manera de verificar el tamaño del proceso de Python? ¿PD?
Davidmytton

algo como ps -o user,pid,vsz="Mem(Kb)" -o cmd $PYTHON_PID, o top (1), debería hacerlo.
Pilcrow


5

Sigo sospechando que su cliente / usuario tiene algún módulo del kernel o controlador cargado que está interfiriendo con la clone()llamada al sistema (¿quizás alguna mejora de seguridad oscura, algo como LIDS pero más oscuro?) O que de alguna manera está llenando algunas de las estructuras de datos del kernel que son necesarios para fork()/clone() para operar (tabla de procesos, tablas de páginas, tablas de descriptores de archivos, etc.).

Aquí está la parte relevante de la fork(2)página de manual:

ERRORES
       EAGAIN fork () no puede asignar suficiente memoria para copiar las tablas de la página principal y asignar una estructura de tareas para el
              niño.

       EAGAIN No fue posible crear un nuevo proceso porque se encontró el límite de recursos RLIMIT_NPROC de la persona que llama. A
              exceda este límite, el proceso debe tener la capacidad CAP_SYS_ADMIN o CAP_SYS_RESOURCE.

       ENOMEM fork () no pudo asignar las estructuras de kernel necesarias porque la memoria es escasa.

Sugiero que el usuario intente esto después de arrancar en un kernel genérico y con solo un conjunto mínimo de módulos y controladores cargados (mínimo necesario para ejecutar su aplicación / script). A partir de ahí, asumiendo que funciona en esa configuración, pueden realizar una búsqueda binaria entre eso y la configuración que presenta el problema. Esta es la solución de problemas estándar de administradores de sistemas 101.

La línea relevante en tu stracees:

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

... Sé que otros han hablado sobre el intercambio y la disponibilidad de memoria (y le recomendaría que configure al menos una pequeña partición de intercambio, irónicamente incluso si está en un disco RAM ... las rutas del código a través del kernel de Linux cuando tiene incluso una pequeña cantidad de intercambio disponible se ha ejercido mucho más ampliamente que aquellos (rutas de manejo de excepciones) en los que no hay intercambio disponible.

Sin embargo, sospecho que esto sigue siendo una pista falsa.

El hecho de que freeinforme 0 (CERO) memoria en uso por el caché y los búferes es muy perturbador. Sospecho que la freesalida ... y posiblemente el problema de su aplicación aquí, son causados ​​por algún módulo del kernel propietario que está interfiriendo con la asignación de memoria de alguna manera.

De acuerdo con las páginas de manual para fork () / clone (), la llamada al sistema fork () debería devolver EAGAIN si su llamada causaría una violación del límite de recursos (RLIMIT_NPROC) ... sin embargo, no dice si se debe devolver EAGAIN por otras infracciones de RLIMIT *. En cualquier caso, si su objetivo / host tiene algún tipo de Vormetric extraño u otra configuración de seguridad (o incluso si su proceso se está ejecutando bajo alguna política de SELinux extraña), entonces podría estar causando esta falla -ENOMEM.

Es bastante improbable que sea un problema normal de Linux / UNIX. Tiene algo fuera de lo normal.


1
El servidor se ejecuta en una plantilla de medios (dv) que usa Virtuozzo para la virtualización.
Davidmytton

Intente buscar en los foros de mensajes de Virtuozzo y en el sistema de seguimiento de errores y, tal vez, busque actualizaciones para el subsistema Virtuozzo.
Jim Dennis

2

¿Ha intentado usar:

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

Pensé que esto me había solucionado exactamente el mismo problema. Pero luego mi proceso terminó siendo asesinado en lugar de fallar al engendrar, lo cual es aún peor ...

Después de algunas pruebas, descubrí que esto solo ocurría en versiones anteriores de Python: sucede con 2.6.5 pero no con 2.7.2

Mi búsqueda me había llevado aquí python-close_fds-issue , pero desarmar closed_fds no había resuelto el problema. Todavía vale la pena leerlo.

Descubrí que Python estaba filtrando descriptores de archivos con solo vigilarlo:

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

Como tú, quiero capturar la salida del comando y quiero evitar errores OOM ... pero parece que la única forma es que la gente use una versión de Python con menos errores. No es ideal...


0

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

He visto un código descuidado que se ve así:

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

Debe verificar si esto es lo que está sucediendo en el código de Python. Errno solo es válido si la llamada al sistema en curso falló.

Editado para agregar:

No dice cuánto tiempo dura este proceso. Posibles consumidores de memoria

  • procesos bifurcados
  • estructuras de datos no utilizadas
  • bibliotecas compartidas
  • archivos mapeados en memoria

2
Sí, pero vemos en la estrategia del OP que la primera falla en la llamada al sistema, de clone (), es ENOMEM como se informó. Este error se conserva a lo largo del tropiezo de poca memoria de Python a través de la construcción de rastreo, aunque la biblioteca C errnose restablece muchas veces a lo largo del camino.
Pilcrow

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.