Sous-processus Python.Popen «OSError: [Errno 12] Impossible d'allouer de la mémoire»

114

Remarque: Cette question a été posée à l'origine ici, mais le délai de prime a expiré même si une réponse acceptable n'a pas été trouvée. Je pose à nouveau cette question en incluant tous les détails fournis dans la question initiale.

Un script python exécute un ensemble de fonctions de classe toutes les 60 secondes à l'aide du module sched :

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

Le script s'exécute en tant que processus démonisé en utilisant le code ici .

Un certain nombre de méthodes de classe appelées dans le cadre de doChecks utilisent le module de sous - processus pour appeler des fonctions système afin d'obtenir des statistiques système:

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

Cela fonctionne bien pendant un certain temps avant que tout le script ne se bloque avec l'erreur suivante:

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 sortie de free -m sur le serveur une fois que le script s'est écrasé est:

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

Le serveur exécute CentOS 5.3. Je ne peux pas reproduire sur mes propres boîtiers CentOS ni avec aucun autre utilisateur signalant le même problème.

J'ai essayé un certain nombre de choses pour déboguer ceci comme suggéré dans la question originale:

  1. Enregistrement de la sortie de free -m avant et après l'appel Popen. Il n'y a pas de changement significatif dans l'utilisation de la mémoire, c'est-à-dire que la mémoire n'est pas utilisée progressivement pendant l'exécution du script.

  2. J'ai ajouté close_fds = True à l'appel Popen mais cela n'a fait aucune différence - le script s'est toujours écrasé avec la même erreur. Suggéré ici et ici .

  3. J'ai vérifié les limites qui montraient (-1, -1) à la fois sur RLIMIT_DATA et RLIMIT_AS comme suggéré ici .

  4. Un article a suggéré que le fait de ne pas avoir d'espace d'échange pourrait en être la cause, mais l'échange est en fait disponible sur demande (selon l'hébergeur Web) et cela a également été suggéré comme une cause bidon ici .

  5. Les processus sont fermés parce que c'est le comportement de l'utilisation de .communicate () tel que sauvegardé par le code source Python et les commentaires ici .

Toutes les vérifications peuvent être trouvées sur GitHub ici avec la fonction getProcesses définie à partir de la ligne 442. Ceci est appelé par doChecks () à partir de la ligne 520.

Le script a été exécuté avec strace avec la sortie suivante avant le 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)                           = ?
Davidmytton
la source
1
runnig hors de «tuyaux» ou de descripteurs de fichiers ou d'une ressource de noyau liée à ceux-ci?
Blauohr le
Vérifiez /var/log/messagesou dmesgcommandez.
mark4o le
Il n'y a rien dans le journal pertinent à ce sujet.
davidmytton
Avez-vous déjà trouvé une solution à cela? J'ai des symptômes très similaires. J'ai beaucoup de mémoire disponible, mais après avoir ajouté le swap (comme certaines de vos réponses le suggèrent), le problème disparaît. Je me demandais simplement si vous aviez découvert quelque chose dans les mois entre alors et maintenant. -- Merci!
dpb
Je rencontre le même problème mais aucune solution - des idées?

Réponses:

88

En règle générale ( par exemple dans les noyaux de vanille), fork/ cloneéchecs avec ENOMEM lieu spécifiquement en raison soit honnête à Dieu hors condition de mémoire insuffisante ( dup_mm, dup_task_struct, alloc_pid, mpol_dup, mm_initetc. croassement), ou parce que security_vm_enough_memory_mmvous avez échoué en application de la politique surdimensionnement .

Commencez par vérifier la vmsize du processus qui n'a pas réussi à fork, au moment de la tentative de fork, puis comparez à la quantité de mémoire libre (physique et swap) en ce qui concerne la politique de surengagement (branchez les nombres.)

Dans votre cas particulier, notez que Virtuozzo a des vérifications supplémentaires dans l' application des surengagements . De plus, je ne suis pas sûr du niveau de contrôle que vous avez réellement, à partir de votre conteneur, sur la configuration de swap et de surengagement (afin d'influencer le résultat de l'application.)

Maintenant, pour aller de l'avant, je dirais qu'il vous reste deux options :

  • passer à une instance plus grande, ou
  • faites un effort de codage pour contrôler plus efficacement l' empreinte mémoire de votre script

Notez que l'effort de codage peut être nul s'il s'avère que ce n'est pas vous, mais un autre gars colocalisé dans une instance différente sur le même serveur que vous exécutez amock.

En ce qui concerne la mémoire, nous savons déjà que subprocess.Popenutilise fork/ clone sous le capot , ce qui signifie qu'à chaque fois que vous l'appelez, vous demandez à nouveau autant de mémoire que Python consomme déjà , c'est-à-dire dans les centaines de Mo supplémentaires, le tout pour ensuite execun exécutable minuscule de 10 Ko tel que freeou ps. Dans le cas d'une politique de surengagement défavorable, vous verrez bientôt ENOMEM.

Les alternatives à forkcela n'ont pas ce problème de copie des tables de page parente, etc. sont vforket posix_spawn. Mais si vous n'avez pas envie de réécrire des morceaux de subprocess.Popenen termes de vfork/ posix_spawn, envisagez de n'utiliser suprocess.Popenqu'une seule fois, au début de votre script (lorsque l'empreinte mémoire de Python est minimale), pour générer un script shell qui exécute ensuite free/ ps/ sleepet quoi que ce soit d'autre dans un boucle parallèle à votre script; interrogez la sortie du script ou lisez-le de manière synchrone, éventuellement à partir d'un thread séparé si vous avez d'autres choses à prendre en charge de manière asynchrone - effectuez votre analyse de données en Python mais laissez le forking au processus subordonné.

CEPENDANT , dans votre cas particulier, vous pouvez ignorer l'appel pset freetout à fait; ces informations sont facilement accessibles en Python directement depuisprocfs , que vous choisissiez d'y accéder vous-même ou via des bibliothèques et / ou des packages existants . Si pset freeétaient les seuls utilitaires que vous utilisiez, vous pouvez vous en débarrasser subprocess.Popencomplètement .

Enfin, quoi que vous fassiez en ce qui le subprocess.Popenconcerne, si votre script perd de la mémoire, vous finirez par frapper le mur. Gardez un œil dessus et recherchez les fuites de mémoire .

vladr
la source
7
J'ai trouvé que l'exécution gc.collect()juste avant subprocess.Popenaide dans les cas où le ramasse-miettes n'avait pas fonctionné depuis un certain temps.
letmaik
J'ai écrit un démon pour gérer la stratégie de script d'assistance: github.com/SeanHayes/errand-boy Je l'utilise en production avec l'un de mes clients et nos problèmes de "Impossible d'allouer de la mémoire" ont disparu.
Seán Hayes
J'apprécierais un diagnostic simple, par exemple en suivant /proc/fd/mapspour déterminer si la mémoire surchargée est en fait le problème
Dima Tisnek
18

En regardant la sortie, free -mil me semble que vous n'avez pas de mémoire d'échange disponible. Je ne sais pas si sous Linux, le swap sera toujours disponible automatiquement à la demande, mais j'avais le même problème et aucune des réponses ici ne m'a vraiment aidé. L'ajout de mémoire d'échange a cependant résolu le problème dans mon cas, donc comme cela pourrait aider d'autres personnes confrontées au même problème, je poste ma réponse sur la façon d'ajouter un échange de 1 Go (sur Ubuntu 12.04 mais cela devrait fonctionner de la même manière pour les autres distributions.)

Vous pouvez d'abord vérifier si une mémoire d'échange est activée.

$sudo swapon -s

s'il est vide, cela signifie qu'aucun échange n'est activé. Pour ajouter un swap de 1 Go:

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

Ajoutez la ligne suivante au fstabpour rendre le swap permanent.

$sudo vim /etc/fstab

     /swapfile       none    swap    sw      0       0 

La source et plus d'informations peuvent être trouvées ici .

Nima
la source
1
Cela a-t-il résolu le même problème ou un autre?
Dima Tisnek
Cela l'a fait pour moi à CentOS 6.4. Face à une erreur lors de l'installation de awstats, merci.
Ruslan Abuzant
Bien que cela m'ait permis d'exécuter le code, cela n'a pas vraiment résolu le problème, qui réside probablement dans une bibliothèque que j'utilise.
philmaweb
1
Vous avez résolu mon problème. Merci! +1
sscirrus
8

swap peut ne pas être le hareng rouge suggéré précédemment. Quelle est la taille du processus python en question juste avant le ENOMEM?

Sous le noyau 2.6, /proc/sys/vm/swappinesscontrôle l'agressivité du noyau pour permuter, et overcommit*classe la quantité et la précision avec laquelle le noyau peut répartir la mémoire avec un clin d'œil et un signe de tête. Comme votre statut de relation Facebook, c'est compliqué .

... mais swap est en fait disponible à la demande (selon l'hébergeur) ...

mais pas en fonction de la sortie de votre free(1)commande, qui n'affiche aucun espace de swap reconnu par votre instance de serveur. Maintenant, votre hébergeur en sait certainement beaucoup plus que moi sur ce sujet, mais les systèmes RHEL / CentOS virtuels que j'ai utilisés ont signalé un échange disponible pour le système d'exploitation invité.

Adaptation de l'article 15252 de la base de connaissances Red Hat :

Un système Red Hat Enterprise Linux 5 fonctionnera très bien sans aucun espace de swap tant que la somme de la mémoire anonyme et de la mémoire partagée du système V est inférieure à environ 3/4 de la quantité de RAM. .... Les systèmes avec 4 Go de RAM ou moins [il est recommandé d'avoir] un minimum de 2 Go d'espace de swap.

Comparez vos /proc/sys/vmparamètres à une installation CentOS 5.3 simple. Ajoutez un fichier d'échange. Ratchet swappinesset voyez si vous vivez plus longtemps.

pilcrow
la source
Quelle est la meilleure façon de vérifier la taille du processus python? ps?
davidmytton le
quelque chose comme ps -o user,pid,vsz="Mem(Kb)" -o cmd $PYTHON_PID, ou top (1), devrait le faire.
Pilcrow le
7

Pour une solution simple, vous pouvez

echo 1 > /proc/sys/vm/overcommit_memory

si vous êtes sûr que votre système dispose de suffisamment de mémoire. Voir Linux sur l'heuristique de validation .

serv-inc
la source
1
Merci beaucoup! Une solution si simple, vous avez sauvé ma journée)
igolkotek
5

Je continue de soupçonner que votre client / utilisateur a chargé un module ou un pilote du noyau qui interfère avec l' clone()appel système (peut-être une amélioration de la sécurité obscure, quelque chose comme LIDS mais plus obscur?) Ou remplit en quelque sorte certaines des structures de données du noyau qui sont nécessaires pour fork()/ clone()pour fonctionner (table de processus, tables de pages, tables de descripteurs de fichiers, etc.).

Voici la partie pertinente de la fork(2)page de manuel:

LES ERREURS
       EAGAIN fork () ne peut pas allouer suffisamment de mémoire pour copier les tables de pages du parent et allouer une structure de tâche pour le
              enfant.

       EAGAIN Il n'a pas été possible de créer un nouveau processus car la limite de ressources RLIMIT_NPROC de l'appelant a été rencontrée. À
              dépasser cette limite, le processus doit avoir la capacité CAP_SYS_ADMIN ou CAP_SYS_RESOURCE.

       ENOMEM fork () n'a pas réussi à allouer les structures de noyau nécessaires car la mémoire est insuffisante.

Je suggère à l'utilisateur d'essayer ceci après le démarrage dans un stock, un noyau générique et avec seulement un ensemble minimal de modules et de pilotes chargés (minimum nécessaire pour exécuter votre application / script). À partir de là, en supposant que cela fonctionne dans cette configuration, ils peuvent effectuer une recherche binaire entre cela et la configuration qui présente le problème. Il s'agit du dépannage standard de sysadmin 101.

La ligne pertinente dans votre straceest:

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

... Je sais que d'autres ont parlé de la disponibilité de swap et de mémoire (et je vous recommanderais de configurer au moins une petite partition de swap, ironiquement même si elle est sur un disque RAM ... les chemins de code à travers le noyau Linux quand il a même un tout petit peu de swap disponible a été exercé beaucoup plus intensivement que ceux (chemins de gestion d'exceptions) dans lesquels il n'y a aucun swap disponible.

Cependant, je soupçonne que c'est toujours un hareng rouge.

Le fait de freesignaler une mémoire 0 (ZERO) utilisée par le cache et les tampons est très inquiétant. Je soupçonne que la freesortie ... et peut-être votre problème d'application ici, sont causés par un module de noyau propriétaire qui interfère d'une manière ou d'une autre avec l'allocation de mémoire.

Selon les pages de manuel de fork () / clone (), l'appel système fork () devrait retourner EAGAIN si votre appel provoquait une violation de la limite de ressources (RLIMIT_NPROC) ... cependant, cela ne dit pas si EAGAIN doit être retourné par d'autres violations de RLIMIT *. Dans tous les cas, si votre cible / hôte a une sorte de paramètres de sécurité étranges Vormetric ou autres (ou même si votre processus s'exécute sous une politique SELinux étrange), cela peut être à l'origine de cet échec -ENOMEM.

Il est peu probable que ce soit un problème Linux / UNIX normal. Il se passe quelque chose de non standard là-bas.

Jim Dennis
la source
1
Le serveur fonctionne sur une base Media Template (dv) qui utilise Virtuozzo pour la virtualisation.
davidmytton le
Essayez de chercher dans les babillards et le système de suivi des bogues de Virtuozzo et, peut-être, recherchez des mises à niveau du sous-système Virtuozzo lui-même.
Jim Dennis
2

Avez-vous essayé d'utiliser:

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

Je pensais que cela avait résolu exactement le même problème pour moi. Mais ensuite, mon processus a fini par être tué au lieu de ne pas apparaître, ce qui est encore pire.

Après quelques tests, j'ai constaté que cela ne se produisait que sur les anciennes versions de python: cela se produit avec 2.6.5 mais pas avec 2.7.2

Ma recherche m'avait conduit ici python-close_fds-issue , mais la désactivation de closed_fds n'avait pas résolu le problème. Cela vaut toujours la peine d'être lu.

J'ai trouvé que python fuyait des descripteurs de fichiers en gardant simplement un œil dessus:

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

Comme vous, je veux capturer la sortie de la commande, et je veux éviter les erreurs MOO ... mais il semble que le seul moyen soit pour les gens d'utiliser une version moins boguée de Python. Pas idéal ...

totaam
la source
0

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

J'ai vu du code bâclé qui ressemble à ceci:

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

Vous devriez vérifier si c'est ce qui se passe dans le code python. Errno n'est valide que si l'appel système en cours a échoué.

Modifié pour ajouter:

Vous ne dites pas combien de temps dure ce processus. Possibles consommateurs de mémoire

  • processus fourchus
  • structures de données inutilisées
  • bibliothèques partagées
  • fichiers mappés en mémoire
codeDr
la source
2
Oui, mais nous voyons de la strace de l'OP que le premier échec de l'appel système - de clone () - est ENOMEM comme cela est rapporté. Cette erreur est préservée le long de la faible mémoire de python par la construction de traceback, même si la bibliothèque C errnoest réinitialisée plusieurs fois en cours de route.
pilcrow