Comment puis-je arrêter rapidement un processus qui provoque un thrashing (en raison d'une allocation de mémoire excessive)?


19

Nous l'avons tous vécu - certains programmes sont invités à faire quelque chose qui nécessite une énorme quantité de mémoire. Il essaie consciencieusement d'allouer toute cette mémoire, et le système commence immédiatement à se débattre, à permuter sans cesse et à devenir lent ou non réactif.

J'ai récemment expérimenté cela sur mon ordinateur portable Ubuntu en raison d'un script Matlab essayant d'allouer une matrice ridiculement énorme. Après environ 5 + minutes de thrashing, j'ai pu Ctrl-F1 sur une console et tuer Matlab. Je préférerais de loin avoir un raccourci clavier qui m'aurait donné immédiatement le contrôle du système et m'aurait permis de tuer le processus incriminé; ou, peut-être, simplement refuser silencieusement d'allouer un si grand tampon.

  1. Quel est le moyen le plus rapide de reprendre le contrôle d'un système Linux qui ne répond plus ou est extrêmement lent à cause d'un échange excessif?

  2. Existe-t-il un moyen efficace d'empêcher un tel échange de se produire en premier lieu, par exemple en limitant la quantité de mémoire qu'un processus est autorisé à essayer d'allouer?

Réponses:


12

Appuyez sur Alt-SysRq-F pour tuer le processus en utilisant le plus de mémoire:

  • La clé SysRq est généralement mappée à la clé d'impression.
  • Si vous utilisez un bureau graphique, vous devrez peut-être appuyer sur Ctrl-Alt-SysRq-F au cas où appuyer sur Alt-SysRq déclencherait une autre action (par exemple, un programme d'instantanés).
  • Si vous utilisez un ordinateur portable, vous devrez peut-être également appuyer sur une touche de fonction.
  • Pour plus d'informations, lisez l' article wikipedia .

5

J'ai créé un script à cet effet - https://github.com/tobixen/thrash-protect

J'ai réussi à exécuter ce script sur des serveurs de production, des postes de travail et des ordinateurs portables. Ce script ne tue pas les processus, mais les suspend temporairement - J'ai eu plusieurs situations plus tard où je suis sûr d'avoir perdu le contrôle en raison de la thrash si ce n'était pas pour ce script simple. Dans le "pire" cas, le processus incriminé sera beaucoup ralenti et sera finalement tué par le noyau (MOO), dans le "meilleur" cas, le processus incriminé sera effectivement terminé ... dans tous les cas, le serveur ou la station de travail restera relativement réactif afin qu'il soit facile d'enquêter sur la situation.

Bien sûr, "acheter plus de mémoire" ou "ne pas utiliser de swap" sont deux réponses alternatives plus traditionnelles à la question "comment éviter le thrashing?", Mais en général elles ont tendance à ne pas fonctionner si bien (l'installation de plus de mémoire peut être non trivial, un processus non autorisé peut consommer toute la mémoire, peu importe la quantité installée, et on peut rencontrer des problèmes de thrash même sans swap lorsqu'il n'y a pas assez de mémoire pour la mise en mémoire tampon / la mise en cache). Je recommande thrash-protect ainsi que beaucoup d'espace de swap.


À propos de la désactivation du swap, selon unix.stackexchange.com/a/24646/9108, ce n'est peut-être pas la meilleure option.
sashoalm

En effet, quelqu'un a fait le même commentaire sur moi, j'ai donc modifié le document de protection contre les thrash à ce stade.
tobixen

4
  1. Quel est le moyen le plus rapide de reprendre le contrôle d'un système Linux qui ne répond plus ou est extrêmement lent à cause d'un échange excessif?

Déjà répondu ci - dessus avec Alt-SysRq-F

  1. Existe-t-il un moyen efficace d'empêcher un tel échange de se produire en premier lieu, par exemple en limitant la quantité de mémoire qu'un processus est autorisé à essayer d'allouer?

Je réponds à cette 2ème partie. Oui, ulimitfonctionne toujours assez bien pour limiter un seul processus. Vous pouvez:

  • fixer une limite souple pour un processus dont vous savez qu'il sera probablement hors de contrôle
  • fixer une limite stricte pour tous les processus si vous voulez une assurance supplémentaire

Aussi, comme brièvement mentionné:

Vous pouvez utiliser des groupes CG pour limiter l'utilisation des ressources et éviter de tels problèmes

En effet, les cgroups offrent un contrôle plus avancé, mais sont actuellement plus compliqués à configurer à mon avis.

Ulimit old school

Une fois éteint

Voici un exemple simple:

$ bash
$ ulimit -S -v $((1*2**20))
$ r2(){r2 $@$@;};r2 r2
bash: xmalloc: .././subst.c:3550: cannot allocate 134217729 bytes (946343936 bytes allocated)

Il:

  • Définit une limite souple de 1 Go d'utilisation globale de la mémoire (ulimit suppose une limite en unité de Ko)
  • Exécute un appel de fonction bash récursif qui mâchera de manière r2(){ r2 $@$@;};r2 r2exponentielle le CPU et la RAM en se doublant infiniment tout en demandant la mémoire de la pile.

Comme vous pouvez le voir, il s'est arrêté lors de la tentative de demande de plus de 1 Go.

Remarque, -vfonctionne sur l'allocation de mémoire virtuelle (total, c'est-à-dire physique + échange).

Protection permanente

Pour limiter l'allocation de mémoire virtuelle, asest l'équivalent de -vfor limits.conf.

Je fais ce qui suit pour me protéger contre tout processus de mauvaise conduite:

  • Définissez une limite d'espace d'adressage fixe pour tous les processus.
  • address space limit = <physical memory> - 256MB.
  • Par conséquent, aucun processus avec une utilisation gourmande de la mémoire ou une boucle active et une fuite de mémoire ne peut consommer TOUTE la mémoire physique.
  • Une marge de 256 Mo est là pour un traitement essentiel avec ssh ou une console.

Bon mot:

$ sudo bash -c "echo -e \"*\thard\tas\t$(($(grep -E 'MemTotal' /proc/meminfo | grep -oP '(?<=\s)\d+(?=\skB$)') - 256*2**10))\" > /etc/security/limits.d/mem.conf"

Pour valider, cela se traduit par ce qui suit (par exemple sur un système de 16 Go):

$ cat /etc/security/limits.d/mem.conf
*   hard    as      16135196
$ ulimit -H -v
161351960

Remarques:

  • Atténue uniquement contre un processus unique allant trop loin avec l'utilisation de la mémoire.
  • N'empêchera pas une charge de travail multi-processus avec une forte pression mémoire provoquant un thrashing (cgroups est alors la réponse).
  • N'utilisez pas d' rssoption dans limits.conf. Il n'est pas respecté par les noyaux plus récents.
  • C'est conservateur.
    • En théorie, un processus peut demander de manière spéculative beaucoup de mémoire mais uniquement utiliser activement un sous-ensemble (plus petit ensemble de travail / utilisation de mémoire résidente).
    • La limite stricte ci-dessus entraînera l'abandon de ces processus (même s'ils auraient sinon pu fonctionner correctement, étant donné que Linux permet de surcharger l'espace d'adressage de la mémoire virtuelle).

Nouveaux groupes CG

Offre plus de contrôle, mais actuellement plus complexe à utiliser:

  • Améliore l'offre ulimit.
    • memory.max_usage_in_bytes peut prendre en compte et limiter la mémoire physique séparément.
    • Alors que ulimit -met / ou rssin limits.confétaient censés offrir des fonctionnalités similaires, mais cela ne fonctionne pas depuis le noyau Linux 2.4.30!
  • Nécessité de permettre à certains indicateurs de CGroup du noyau dans bootloader: cgroup_enable=memory swapaccount=1.
    • Cela ne s'est pas produit par défaut avec Ubuntu 16.04.
    • Probablement en raison de certaines implications en termes de performances de frais généraux supplémentaires.
  • Les éléments cgroup / systemd sont relativement nouveaux et changent un peu, donc le flux en amont implique que les fournisseurs de distribution Linux ne l'ont pas encore rendu facile à utiliser. Entre 14.04LTS et 16.04LTS, l'outillage de l'espace utilisateur pour utiliser les groupes de contrôle a changé.
    • cgm semble maintenant être l'outil de l'espace utilisateur officiellement pris en charge.
    • Les fichiers d'unité systemd ne semblent pas encore avoir de valeurs par défaut "fournisseur / distribution" pour prioriser des services importants comme ssh.

Par exemple, pour vérifier les paramètres actuels:

$ echo $(($(cat /sys/fs/cgroup/memory/memory.max_usage_in_bytes) / 2**20)) MB
11389 MB
$ cat /sys/fs/cgroup/memory/memory.stat
...

Par exemple pour limiter la mémoire d'un seul processus:

$ cgm create memory mem_1G
$ cgm setvalue memory mem_1G memory.limit_in_bytes $((1*2**30))
$ cgm setvalue memory mem_1G memory.memsw.limit_in_bytes $((1*2**30))
$ bash
$ cgm movepid memory mem_1G $$
$ r2(){ r2 $@$@;};r2 r2
Killed

Pour le voir en action mâcher de la RAM en tant que processus d'arrière-plan, puis se faire tuer:

$ bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2' & while [ -e /proc/$! ]; do ps -p $! -o pcpu,pmem,rss h; sleep 1; done
[1] 3201
 0.0  0.0  2876
 102  0.2 44056
 103  0.5 85024
 103  1.0 166944
 ...
98.9  5.6 920552
99.1  4.3 718196
[1]+  Killed                  bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2'

Notez la croissance exponentielle (puissance de 2) des demandes de mémoire.

À l'avenir, espérons voir "distro / vendors" préconfigurer les priorités et les limites du groupe de contrôle (via les unités systemd) pour des choses importantes comme SSH et la pile graphique, de sorte qu'elles ne soient jamais affamées de mémoire.


2

Vous pourrez peut-être appuyer sur Ctrl- zpour suspendre le programme. Ensuite, vous pouvez le faire kill %1(ou quel que soit le numéro de travail ou vous pouvez utiliser le PID).

Vous pouvez utiliser la ulimitcommande pour essayer de limiter la quantité de mémoire disponible pour un processus.


Ctrl-Z est agréable, mais généralement j'utilise une interface graphique Matlab et j'ai perdu la trace du terminal de contrôle, donc je n'ai pas de moyen facile d'émettre la touche Ctrl-Z. Ce serait bien si l'interface graphique avait un raccourci pour envoyer SIGSTOP à n'importe quelle application qui a le focus!
nibot

Vous pouvez exécuter kill -STOP <pid>ce qui fera la même chose que Ctrl-Z.
hlovdal le

Oui, mais tout le problème est que, dans une telle situation, le système est si peu réactif qu'il faut beaucoup de temps (ou une éternité) pour accéder à une invite de commande.
nibot

1

Vous pouvez utiliser CGroups pour limiter l'utilisation des ressources et éviter de tels problèmes: https://en.wikipedia.org/wiki/Cgroups


Veuillez inclure les informations essentielles dans votre réponse et utiliser le lien uniquement pour l'attribution et la lecture ultérieure. Ce lien décrit ce qu'est CGroups, mais il n'est pas évident à partir du lien comment l'utiliser réellement pour résoudre le problème. Pouvez-vous développer votre réponse pour décrire la solution à la question? Merci.
fixer1234

0

Ce serait bien si l'interface graphique avait un raccourci pour envoyer SIGSTOP à n'importe quelle application qui a le focus!

Il y a toujours la xkillcommande classique (de xorg-x11-apps-7.4-14.fc14.src.rpm sur mon système). Je suppose qu'il ne devrait pas être trop difficile de créer un clone qui envoie SIGSTOP au lieu de tuer la fenêtre cible.


Comment puis-je faire démarrer rapidement xkill en appuyant sur une combinaison de touches?
nibot

Je ne suis pas sûr. Je suppose que gnome et KDE ont une fonctionnalité de raccourci global qui peut être utilisée pour lancer des programmes.
hlovdal
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.