Comment puis-je empêcher Perl de consumr des tonnes de mémoire lorsque des fourches d’enfant d’un processus parent important sont fermées?

Le contexte:

J’ai un processus Perl multi-forking (5.16) qui fonctionne sous Linux. Le fork parent charge une très grande quantité de code Perl (via use/require ) et alloue beaucoup de structures de données (plusieurs Go). Il crée ensuite de nombreuses fourchettes enfants, qui travaillent toutes en parallèle. Ceci est fait pour réduire l’empreinte mémoire du processus pendant son exécution, car la nature de la copie sur écriture de fork() signifie que les enfants peuvent utiliser les données que le parent possède sans que chacune conserve sa propre image de mémoire importante.

Problème:

Tout cela fonctionne bien jusqu’à ce que j’essaye de fermer le groupe de processus. Lorsque j’interromps le parent (le signal se propage à tous les enfants), la mémoire du serveur exécutant le code se remplit immédiatement, il commence à permuter et les autres processus du serveur s’arrêtent. Quand un fork de copy-on-write est arrêté, Perl semble essayer de réallouer toute la mémoire réclamée dans le parent afin de pouvoir le marquer free ou quelque chose.

Question:

Comment puis-je empêcher ce blocage sur arrêt? Y a-t-il un moyen de dire aux enfants que les fourchettes n’essayeront que de traverser et de récupérer la mémoire allouée par ces fourchettes?

L’affectation des pages de mémoire est due à la désallocation des variables à la sortie. Ceci est nécessaire pour avoir des destructeurs appelés.

L’appel de POSIX::_exit() terminera immédiatement, en ignorant la désallocation par variable, mais aussi en ignorant les appels de destructeurs.

J’ai accepté la réponse de @ ikegami, car elle répond directement à la question.

Je poste ceci parce que ma “solution” (vraiment un moyen d’optimiser une partie du problème) pourrait être utile aux autres.

Le correctif final dans mon cas était un changement de paradigme: je me suis rendu compte que le problème n’était pas que tout processus Perl absorbait beaucoup de mémoire lors de l’arrêt de Fork, mais .

Lorsque mon processus parent a reçu l’instruction “shutdown”, il a immédiatement envoyé un message “shutdown” à tous ses enfants et ils ont tous fini ce qu’ils faisaient et se sont arrêtés à peu près au même moment. Avec des dizaines à des centaines de processus enfants qui s’arrêtent en même temps, la surcharge de mémoire est trop importante.

La solution consistait à faire de l’arrêt un processus en deux phases: tout d’abord, le processus parent envoyait un message “Arrêtez ce que vous faites” à tous ses enfants pour que la logique métier cesse de s’exécuter à un moment prévisible. Il a envoyé ce message à tous les enfants à la fois / dans une boucle très rapide. Ensuite, il a arrêté les enfants un par un . Il a envoyé une interruption à chaque enfant, appelé waitpid dessus jusqu’à ce qu’il soit terminé, puis est passé au suivant.

De cette manière, l’empreinte mémoire induite par l’arrêt le plus défavorable (avec p représentant l’empreinte mémoire pré-diapason et f représentant le nombre de fourches enfants) était de 2p plutôt que de fp .

Cette solution ne fonctionnera pas dans les cas où la consommation de mémoire 2p représente toujours un coût inacceptable.

Deux optimisations ont été ajoutées: contrôles d’expiration / arrêt forcé dans le cas d’enfants entêtés / brisés et sleep conditionnel entre des arrêts d’enfant si l’arrêt de l’enfant précédent a forcé le système à commencer à échanger. Le sleep donné au système le temps de respirer / de sortir les pages des échanges.

Là encore, il s’agit d’une optimisation du problème et non d’une réponse. La vraie réponse est @ ikegami.