Comment résoudre ce problème de memory avec élégance?

J'ai un ordinateur portable Linux (test Debian) standard, avec une partition swap.

Je fais beaucoup d'expériences avec lui. Certains d'entre eux ont vraiment faim de memory et la façon dont Linux se comporte par défaut est un problème pour moi … Donnons un exemple stupide:

  1. Asseyez-vous devant l'ordinateur portable
  2. Ouvrir un terminal
  3. Tapez python , puis a = [0]*100000000

Maintenant, les chances sont élevées que vous n'aurez pas assez de RAM pour gérer cette grande list. Linux remplira la RAM, puis le swap et, quelques minutes plus tard, le tueur du MOO sera déclenché et tue (presque) des services randoms et j'espère que si vous appuyez sur Ctrl + C au bon moment, python et si le le terminal a encore eu le focus, l'ordinateur redeviendra réactif.

Je voudrais imposer certaines limites de memory pour éviter que l'échange non désiré et de refuser à un process le droit d'allouer plus de memory que j'ai (en RAM). Si la request de memory est inférieure à une certaine limite ou demandée par root, il suffit de tuer le process le plus gourmand en memory de n'importe quel user sauf root.

ulimit -Sv [mem] J'entends dans le dos!

Ho Ho! "Utiliser cgroups via cgexec !" quelqu'un dit à la première rangée!

Oui, vous avez raison: ce sont en effet de très bonnes solutions. Mais:

  • Ils ne s'appliquent pas à l'échelle du système
  • Les limites sont définies par process
  • Les limites sont statiques, sans tenir count de la quantité réelle d'une RAM libre (AFAIK)
  • Ici et là , ils disent que ce ne sont pas vraiment une bonne solution pour imposer des limites ssortingctes.

Ce que je voudrais, c'est que le kernel dise: "Vous appartenez à l'user foo (pas root), vous utilisez beaucoup de memory et nous allons manquer de memory. Désolé mec … meurs maintenant!"

Ou: "Qu'est-ce que tu fais? Tu as besoin de x MB et il n'y a que y MB disponible. dit non, pas de memory pour toi, si tu insistes, tu vas mourir!

Quelqu'un a suggéré dans votre entendez cgroups . Eh bien, essayez de chercher cette direction car elle peut vous fournir:

  • appliqué à un groupe de tâches que vous choisissez (donc pas à l'échelle du système mais pas par process)
  • les limites sont définies pour le groupe
  • les limites sont statiques
  • ils peuvent imposer une limite ssortingcte sur la memory et / ou la memory + swap

Quelque chose comme ça pourrait vous rapprocher de vos objectives :

 group limited { memory { memory.limit_in_bytes = 50M; memory.memsw.limit_in_bytes = 50M; } } 

Cela indique que les tâches de ce groupe de cgroup peuvent utiliser au maximum 50M de memory et 50M de memory + swap, donc quand la memory est pleine, elle ne sera pas échangée, mais si la memory n'est pas pleine et que certaines données pourraient être mappées échange, cela pourrait être autorisé.

Voici un extrait de la documentation de la memory du cgroup :

En utilisant la limite memsw, vous pouvez éviter le MOO du système qui peut être causé par une pénurie de swap.

Je rencontre souvent le même problème. Mon stream de travail général implique un calcul lourd dans MATLAB. Parfois, je tenterai par inadvertance d'allouer une nouvelle variable qui dépasse la quantité de memory disponible. Le système se bloque et je dois généralement redémarrer la machine pour redémarrer le travail. : P

Dans mon cas, et cela ressemble à la vôtre aussi, je n'étais pas tellement préoccupé par la limitation de la quantité de memory utilisée par MATLAB à un montant statique – je souhaitais ne pas avoir de machine congelée et j'étais prêt à sacrifier mon process MATLAB afin de préserver la réactivité du système.

Inspiré par une réponse à ce message , j'ai écrit le script suivant (je l'ai appelé watch_memory.sh):

 #!/bin/bash MONITOR=$(free | grep 'buffers/cache:') MEM_USED=$(echo $MONITOR | awk '{ print $3 }') MEM_FREE=$(echo $MONITOR | awk '{ print $4 }') MEM_PERC=$(( 100*MEM_USED / (MEM_FREE+MEM_USED) )) while :; do if [ "$MEM_PERC" -gt "95" ] then kill $1 echo "$1 killed for using too much memory." exit fi sleep 1 MONITOR=$(free | grep 'buffers/cache:') MEM_USED=$(echo $MONITOR | awk '{ print $3 }') MEM_FREE=$(echo $MONITOR | awk '{ print $4 }') MEM_PERC=$(( 100*MEM_USED / (MEM_FREE+MEM_USED) )) done 

Ce script vérifie chaque seconde le pourcentage de memory libre. Lorsque le système s'épuise, votre pid "bouc émissaire" (passé en argument au script) est tué.

Sans ajuster la priorité (script) du script, il a fallu environ 10-20 secondes pour que le bouc émissaire soit tué, mais cela fonctionnait toujours. L'exécution du script avec une priorité négative a donné lieu à un kill immédiat après violation (11916 dans cet exemple est le pid que je veux tuer si je n'ai plus de memory):

 sudo nice -n -5 bash watch_memory.sh 11916 

J'espère que ça aide!