Comment puis-je limiter la quantité de mémoire disponible pour un processus?

11

Je développe un programme en cours; il finit parfois par allouer de très grandes quantités de mémoire (>> 10G sur une machine avec 8G de mémoire physique), ce qui fait que le système ne répond plus. Je souhaite limiter la quantité de mémoire que le processus peut allouer. La façon habituelle de procéder est la suivante:

ulimit -m 4000000 ; ./myprogram

... ce qui devrait tuer mon programme s'il essaie d'utiliser plus de 4 Go de mémoire.

Sous OS X El Capitan, cela semble n'avoir aucun effet; même ulimit -m 1(limiter tous les programmes à seulement 1 Ko de mémoire!) est inefficace.

Comment puis-je définir une limite supérieure sur la mémoire disponible pour un processus particulier?

cpcallen
la source
Quand vous dites La façon habituelle dont je ferais cela , que voulez-vous dire? Plus précisément, quand faites-vous cela habituellement? Et quand vous le faites, voulez-vous dire dans Mac OS X El Capitan ou dans un autre environnement? Pouvez-vous donner un exemple de la réussite de son utilisation? Fondamentalement, j'essaie simplement de clarifier si ce processus fonctionne normalement pour vous, mais ne fonctionne tout simplement pas pour ce programme particulier? Ou est-ce que cela ne fonctionne pas du tout pour vous, mais vous pensez que cela devrait?
Monomeeth
1
Par "la façon habituelle de faire cela", je veux dire la façon dont je ferais cela sur d'autres versions d'Unix. Je note que je viens de découvrir que ulimit -mne fonctionne plus sous Linux (> 2.4.30), mais ulimit -vfonctionne toujours comme prévu. (Comme ulimit -m, ulimit -vsemble également n'avoir aucun effet sur OS X.)
cpcallen
Cela semble que vous ayez une fuite de mémoire dans le programme que vous écrivez et que vous devez faire une meilleure récupération de place. Avez-vous lu sur la gestion de la mémoire en cours?
Todd Dabney
1
Non, pas une fuite de mémoire - juste une recherche graphique d'un espace d'état potentiellement très grand. Je pourrais ajouter du code pour abandonner la recherche si les différentes structures internes deviennent trop grandes, mais je m'attendais à pouvoir faire la même chose (empêcher la machine d'être coincée par de grandes entrées) avec un shell à une ligne.
cpcallen

Réponses:

1

Il existe deux approches pour limiter votre utilisation de la mémoire: ex post facto et préemptive. Autrement dit, vous pouvez essayer de tuer votre programme une fois qu'il est devenu trop volumineux, ou vous pouvez le programmer pour ne pas devenir trop volumineux en premier lieu.

Si vous insistez sur l'approche ex post facto, vous pouvez utiliser le script Bash suivant. Ce script trouve d'abord la quantité de mémoire (définie par la "taille de l'ensemble résident") utilisée par le processus avec pid processid, filtre toutes les données non numériques à l'aide de grep et enregistre la quantité en tant que variable n. Le script vérifie ensuite si n est supérieur à votre x spécifié. Si c'est le cas, le processus avec processid pid est tué.

Notez s'il vous plaît:

  1. Vous devez remplacer <pid>par l'ID de processus de votre programme.
  2. Vous devez remplacer <x>par la taille rss = "resident set size" (c'est-à-dire la taille réelle de la mémoire) que vous ne voulez pas que le programme dépasse.

n=$(ps -<pid> -o rss | grep '[0-9]') if [ $n -gt <x> ]; then kill -9 <pid>; fi

Si vous voulez que cela s'exécute toutes les y secondes, insérez-le simplement dans une boucle et dites-lui d'attendre y secondes après chaque itération. Vous pouvez également écrire une commande similaire à l'aide de top. Votre point de départ serait top -l 1|grep "<pid>"|awk '{print $10}'.

La réponse de @ kenorb m'a aidé avec mon script


Bien que je crois que cela réponde à la question, à long terme, je pense qu'il est préférable de concevoir une programmation pour adopter une approche préventive en utilisant l'allocation de mémoire manuelle.

Tout d'abord, êtes-vous sûr que l'utilisation de la mémoire est vraiment un problème? La documentation Go indique:

L'allocateur de mémoire Go réserve une grande région de mémoire virtuelle comme arène pour les allocations. Cette mémoire virtuelle est locale au processus Go spécifique; la réservation ne prive pas d'autres processus de mémoire.

Si vous pensez toujours que vous avez un problème, je vous encourage à gérer manuellement votre mémoire comme cela se fait dans le langage de programmation C. Puisque go est écrit en C, je soupçonnais qu'il y aurait des moyens d'entrer dans la gestion / les allocations de mémoire C, et effectivement il y en a. Voir ce dépôt github qui,

vous permet de faire une gestion manuelle de la mémoire via l'allocateur C standard pour votre système. C'est une mince pellicule au-dessus de malloc, calloc et sans. Voir man malloc pour plus de détails sur ces fonctions pour votre système. Cette bibliothèque utilise cgo.

Le cas d'utilisation est donné comme suit:

Pourquoi voudriez-vous cela?

Lorsqu'un programme provoque une pression mémoire ou que le système manque de mémoire, il peut être utile de contrôler manuellement les allocations et désallocations de mémoire. Go peut vous aider à contrôler les allocations, mais il n'est pas possible de désallouer explicitement les données inutiles.

Cela semble être une meilleure solution à long terme.

Si vous souhaitez en savoir plus sur C (y compris la gestion de la mémoire), le langage de programmation C est la référence standard.

Evan Rosica
la source
Je suis sûr que l'utilisation de la mémoire est vraiment un problème. Lorsque le programme est devenu de façon inattendue> 2 fois la taille de la mémoire physique, la machine est devenue presque entièrement inactive en raison du débordement de pages. Il m'a fallu environ une heure entre le moment où j'ai appuyé sur ^ C et le moment où macOS a recommencé à répondre aux clics de souris; en attendant, la seule preuve qu'il n'était pas gelé était le bruit silencieux du disque dur qui tournait rapidement.
cpcallen
C'est probablement une solution raisonnable dans la pratique, mais contrairement à ulimit sur les systèmes d'exploitation UNIX (non Darwin), cela dépend de la capacité d'allouer suffisamment de mémoire en temps opportun pour réussir à exécuter la commande kill. Je préfère vraiment que les limites de taille de processus soient appliquées par le noyau.
cpcallen
@cpcallen faisant des recherches, il semble que "le paramètre -m pour ulimit n'ait aucun effet sur les systèmes Linux avec des versions de noyau plus récentes que 2.4.30." Il semble qu'OSX ait également repris ce changement. Essayez l'option -v pour limiter l'espace d'adressage
Evan Rosica