Comprendre les erreurs d’allocation de mémoire et de fork Python

J’ai une application Python intensive en mémoire (entre des centaines de Mo à plusieurs Go).
J’ai deux excellents exécutables Linux que l’application principale doit exécuter, par exemple

child = Popen("make html", cwd = r'../../docs', stdout = PIPE, shell = True) child.wait() 

Lorsque je lance ces utilitaires externes (une fois, à la fin du long processus principal exécuté) en utilisant subprocess.Popen je reçois parfois OSError: [Errno 12] Cannot allocate memory .
Je ne comprends pas pourquoi … Le processus demandé est minuscule!
Le système a suffisamment de mémoire pour plusieurs autres shells.

J’utilise Linux (Ubuntu 12.10, 64 bits), donc je suppose que les appels de sous-processus Fork.
Et Fork transforme mon processus existant, doublant ainsi la quantité de mémoire consommée, et échoue?
Qu’est-il arrivé à “copie sur écriture”?

Puis-je créer un nouveau processus sans fourchette (ou du moins sans copier la mémoire – en commençant frais)?

En relation:

La différence entre fork (), vfork (), exec () et clone ()

fork () & comportement d’allocation de mémoire

Python subprocess.Popen erroring with OSError: [Errno 12] Impossible d’allouer de la mémoire après une période de temps

Erreur d’allocation de mémoire Python à l’aide du sous-processus.Popen

Il ne semble pas qu’une véritable solution soit à venir (c.-à-d. Une implémentation alternative du sous-processus qui utilise vfork). Alors pourquoi pas un hack mignon? Au début de votre processus, générez un esclave avec une empreinte mémoire réduite, prêt à engendrer vos sous-processus et à maintenir une communication ouverte tout au long du processus principal.

Voici un exemple d’utilisation de rfoo ( http://code.google.com/p/rfoo/ ) avec un socket unix nommé rfoosocket (vous pouvez évidemment utiliser d’autres types de connexion supportés par rfoo ou une autre bibliothèque RPC):

Serveur:

 import rfoo import subprocess class MyHandler(rfoo.BaseHandler): def RPopen(self, cmd): c = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) c.wait() return c.stdout.read() rfoo.UnixServer(MyHandler).start('rfoosocket') 

Client:

 import rfoo # Waste a bunch of memory before spawning the child. Swap out the RPC below # for a straight popen to show it otherwise fails. Tweak to suit your # available system memory. mem = [x for x in range(100000000)] c = rfoo.UnixConnection().connect('rfoosocket') print rfoo.Proxy(c).RPopen('ls -l') 

Si vous avez besoin d’interaction coprocess en temps réel avec vos sous-processus générés, ce modèle ne fonctionnera probablement pas, mais vous pourrez peut-être le pirater. Vous voudrez probablement nettoyer les arguments disponibles qui peuvent être transmis à Popen en fonction de vos besoins spécifiques, mais cela devrait être relativement simple.

Vous devriez également trouver facile de lancer le serveur au début du client et de gérer le fichier de socket (ou le port) à nettoyer à la sortie.