Как автоматически завершить процесс с наибольшей загрузкой ЦП?

Вопрос или проблема

Иногда программы могут зависать в фоновом режиме и вызывать высокую загрузку процессора. Есть ли способ программно определить, какой процесс в данный момент вызывает наибольшую нагрузку на CPU, и завершить его?

Существует ряд команд Unix, которые, вероятно, лучше подойдут для этого типа работы, если вы их знаете.

  • pgrep
  • pkill
  • killall

Вы можете использовать эти инструменты, чтобы ваши “атаки” были более целенаправленными, особенно в ситуациях, когда вы знаете имя проблемного процесса.

killall

У меня есть повторяющаяся проблема с Chrome, когда его в конечном итоге нужно завершать. Обычно я выполняю эту команду, чтобы eradicate все из них.

$ killall chrome

pgrep & pkill

Но я также могу сделать это, чтобы завершить только самый новый процесс:

# для перечисления
$ pgrep -n chrome
23108

# для завершения
$ pkill -n chrome

Убийство на основе вашей командной строки

Вы также можете добавить переключатель -f, чтобы достичь тех процессов, которые имеют длинные аргументы пути, на которые вы предпочли бы сослаться, а не только на имя их исполняемого файла.

Например, скажем, у меня есть эти процессы:

$ ps -eaf | grep some
saml     26624 26575  0 22:51 pts/44   00:00:00 some weird command
saml     26673 26624  0 22:51 pts/44   00:00:00 some weird command's friend
saml     26911 26673  8 22:54 pts/44   00:00:00 some weird command's friend

Это просто оболочки Bash с их ARGV0, установленным на эти имена. Кстати, я создал эти процессы, используя этот трюк:

$ (exec -a "some weird command name's friend" bash)

Идти за друзьями

Но допустим, у меня их много, и я хочу пойти только за определенным набором из них, потому что в их командных строках есть “friend”. Я мог бы сделать это:

$ pgrep -f friend
26673
26911

Идти за самым молодым другом

И если их было несколько, и я хотел бы пойти за новым, добавьте переключатель -n обратно в смесь:

$ pgrep -fn friend
26911

Вы также можете использовать регулярные выражения при использовании переключателя -f, так что такие команды будут работать, например:

$ pgrep -f "weird.*friend"
26673
26911

Отображение их имен

Вы можете дважды проверить имена процессов с помощью переключателя -l:

$ pgrep -f "weird.*friend" -l
26673 some weird command's friend
26911 some weird command's friend

Контроль вывода

Или скажите pgrep, чтобы перечислить идентификаторы процессов, разделенные запятой (,):

$ pgrep -f "weird.*friend" -d,
26673,26911

Вы можете делать крутые вещи, как это:

$ ps -fp $(pgrep -f weird -d,)
UID        PID  PPID  C STIME TTY          TIME CMD
saml     26624 26575  0 22:51 pts/44   00:00:00 some weird command
saml     26673 26624  0 22:51 pts/44   00:00:00 some weird command's friend
saml     26911 26673  0 22:54 pts/44   00:00:00 some weird command's friend

Так как же мне убить процесс с высокой загрузкой CPU?

Я бы использовал вышеуказанные методы, чтобы более избирательно подходить к процессу с высокой загрузкой CPU. Вы можете использовать подход завершения, используя эти методы:

# новейшие парни
$ pkill -nf vlc ; pkill -nf opensnap

# завершить всех этих
$ killall vlc; killall opensnap

Посмотрите на их загрузку CPU:

$ top -b -n 1 | grep -E $(pgrep -f "weird.*friend" -d\|) | grep -v grep
26911  0.1  112m 106m 6408  848 4900 1512    0    0 S  20   0  0.0 some weird command's friend                                     
26673  0.1  112m 106m 6392  848 5020 1504    0    0 S  20   0  0.0 some weird command's friend 

Здесь я изменил разделитель с запятой (,), т.е. этот переключатель -d,, на вертикальную черту (|), т.е. этот переключатель -d\|, чтобы я мог использовать его в grep. Это вернет идентификаторы процессов так:

$ pgrep -f "weird.*friend" -d\|
26673|26911

Затем мы вставляем их в команду grep -E ..., чтобы отфильтровать вывод из top на основе определенных идентификаторов процессов.

Это может показаться слишком сложным, но теперь мы точно знаем, что идентификаторы процессов, которые мы используем, относятся только к определенному процессу с именем “weird.*friend”.

Отсюда вы можете найти процесс с наивысшей загрузкой CPU и завершить его, если действительно хотите пойти этим путем.

Более целенаправленный подход к высокой загрузке CPU

$ top -b -n 1 | grep -E $(pgrep -f "weird.*friend" -d\|) | \
    grep -v grep | sort -nk14,14 | tail -1
26911  0.1  112m 106m 6408  848 4900 1512    0    0 S  20   0  0.0 some weird command's friend                                     

Выше показан отсортированный вывод из top по колонке CPU (14-й). Он отсортирован от наименьшего к наибольшему, поэтому мы берем последнюю строку (tail -1), которая будет процессом с наивысшей загрузкой CPU среди процессов “weird.*friend”.

Программа “and”, Auto-Nice Daemon может быть настроена на выполнение чего-то подобного.

Вы настраиваете список с несколькими конкретными известными нарушителями и тремя уровнями изменения приоритета (чтобы вы могли постепенно ужесточать изменение приоритета), но любой из которых мог бы быть завершением процесса, хотя это обычно резервируется как последняя мера.

Не всегда легко регулировать вещи так, чтобы достичь определённых уровней загрузки CPU, но есть другие инструменты, которые могут помочь (и помочь избежать завершения нарушающего процесс, предотвращая правонарушение), такие как cpulimit и предварительное запуск программ с nice и ionice.

Отредактированный скрипт

@msw, @sim и другие пользователи подняли обоснованные вопросы относительно концепции моего скрипта. Вдохновленный ответом @sim и замечаниями msw, я сел и пересмотрел, как решить мою конкретную проблему (несколько известных процессов, которые время от времени создают проблемы). Вот что я придумал:

#!/bin/bash

# пытается завершить процесс с наивысшей загрузкой CPU
# (если он является частью указанного списка нарушителей)

TROUBLEMAKERS="vlc opensnap glxgears stress"

sleep 1 # подождите несколько секунд (на всякий случай)

TOPPROCESS=$(top -b -n 1 | sed 1,6d | sed -n 2p)
TOPPID=$(echo "$TOPPROCESS" | awk '{print $1}')
TOPNAME=$(echo "$TOPPROCESS" | awk '{print $12}')

if [[ "$TROUBLEMAKERS" == *"$TOPNAME"* ]]
  then
      echo "Причина высокой загрузки CPU: "$TOPNAME" ("$TOPPID")"
      echo "В списке нарушителей. Завершаем..."
      kill -9 $TOPPID
  else
      echo "Причина высокой загрузки CPU: "$TOPNAME" ("$TOPPID")"
      echo "Нет в списке нарушителей. Выход..."
      exit 1
fi

exit 0

В отличие от предыдущего скрипта, этот будет завершать процесс с наивысшей загрузкой CPU, только если его имя совпадает с рядом известных нарушителей (процессы, которые склонны зависать в вашей системе).


Оригинальный скрипт

Вот простой скрипт, который определит процесс, вызывающий наивысшую моментальную загрузку CPU в системе и завершит его (за исключением Xorg, который вызовет сбой графического интерфейса):

#!/bin/bash

# пытается завершить процесс с наивысшей загрузкой CPU
# (если это не Xorg)

sleep 1 # подождите несколько секунд (на всякий случай)

TOPPROCESS=$(top -b -n 1 | sed 1,6d | sed -n 2p)
TOPPID=$(echo "$TOPPROCESS" | awk '{print $1}')
TOPNAME=$(echo "$TOPPROCESS" | awk '{print $12}')

if [ "$TOPNAME" != "Xorg" ]
  then
      kill -9 $TOPPID
  else
      echo "Загрузка CPU вызвана Xorg. Выход."
      exit 1
fi

exit 0

Фрагмент TOPPROCESS основан на этой записи на commandlinefu.com.

#!/bin/bash
pid=$(ps -eo %cpu,pid --sort -%cpu | head -n 2 | awk '{print $1 " " $2}')
if [[ -n $pid ]]; then
    kcpu=$(echo $pid | awk '{print $3}')
    kpid=$(echo $pid | awk '{print $4}')
    ift=$(echo "90"'<'$kcpu | bc -l)
    if [ $ift -eq "0" ]; then
        echo "kpid = $kpid"
        kill $kpid
    fi
else
echo "Не существует"
fi

Совместил предыдущие ответы (для своих целей). Может быть, будет также полезно:

#!/bin/bash

# Убить процессы с загрузкой CPU выше CPU_USAGE_LIMIT.
# (если он является частью указанного списка TROUBLEMAKERS_REGEXP)

TROUBLEMAKERS_REGEXP="^(vlc|opensnap|glxgears|stress)$"

TOP_PROCESSES=10
CPU_USAGE_LIMIT=90

COUNTER=0
IFS=$(echo -en "\n\b")
# Получить TOP_PROCESSES (отсортировать по CPU, исключить заголовок)
for rr in `ps -eo %cpu,pid,comm --sort -%cpu | tail -n +2 | head -n ${TOP_PROCESSES} | awk '{print $1 " " $2 " " $3}'`; do
    l_cpu=`echo $rr | awk '{print $1}'`
    l_pid=`echo $rr | awk '{print $2}'`
    l_command=`echo $rr | awk '{print $3}'`
    # сравнить использование CPU процессов с лимитом CPU
    result=`echo "${l_cpu} >= ${CPU_USAGE_LIMIT}" | bc -l`
    if [[ "${result}" = "1" ]]; then
        echo "${l_command}: Найден PID [${l_pid}] с использованием CPU [${l_cpu}] > ${CPU_USAGE_LIMIT}%"
        # Он в списке?
        if [[ "${l_command}" =~ ${TROUBLEMAKERS_REGEXP} ]];then
            echo "${l_command}: Завершаем PID [${l_pid}]."
            kill ${l_pid}
        else
            echo "${l_command}: Пропущен PID [${l_pid}]."
        fi
    else
        # первый процесс с использованием CPU < лимита CPU => разорвать цикл
        if [[ $COUNTER -eq 0 ]];then
            echo "Нет процессов с использованием CPU ограниченным [${CPU_USAGE_LIMIT}]."
        else
            echo "Нет больше процессов с использованием CPU ограниченным [${CPU_USAGE_LIMIT}]."
        fi
        break;
    fi
    COUNTER=$((COUNTER + 1))
done

Ответ или решение

Автоматическое завершение процессов с высоким загрузкой CPU является важной задачей для поддержания производительности системы. В данной инструкции мы рассмотрим, как это сделать на Unix-системах с использованием команд top, ps, kill и других утилит.

1. Использование команды top для определения процесса с высоким CPU

Команда top позволяет мониторить активные процессы и их использование ресурсов в реальном времени. Для автоматизации этого процесса вы можете использовать команду top вместе с другими инструментами.

2. Скрипт для завершения процесса с высоким использованием CPU

Вы можете создать простой скрипт на Bash, который будет определять и завершать процесс с максимальной загрузкой CPU. Вот пример такого скрипта:

#!/bin/bash

# Установка предела загрузки CPU
CPU_USAGE_LIMIT=90

# Получение информации о процессе с самой высокой загрузкой CPU
TOPPROCESS=$(ps -eo %cpu,pid,comm --sort=-%cpu | sed -n '2p')
TOPCPU=$(echo "$TOPPROCESS" | awk '{print $1}')
TOPPID=$(echo "$TOPPROCESS" | awk '{print $2}')
TOPNAME=$(echo "$TOPPROCESS" | awk '{print $3}')

# Проверка, превысила ли загрузка CPU установленный предел
if (( $(echo "$TOPCPU > $CPU_USAGE_LIMIT" | bc -l) )); then
    echo "Процесс: $TOPNAME (PID: $TOPPID) использует $TOPCPU% CPU, превышая лимит."
    # Завершение процесса
    kill -9 $TOPPID
    echo "Процесс $TOPNAME с PID $TOPPID был завершен."
else
    echo "На данный момент нет процессов с загрузкой выше $CPU_USAGE_LIMIT%."
fi

3. Настройка скрипта

  1. Создайте файл с расширением .sh, например kill_high_cpu.sh, и вставьте в него указанный выше код.
  2. Дайте права на исполнение скрипта:
    chmod +x kill_high_cpu.sh
  3. Запускайте скрипт периодически (например, через cron) для автоматического мониторинга.

4. Использование регулярных выражений для целевых процессов

Если вы хотите завершать только определенные "проблемные" процессы, можно добавить проверку на наличие их имен в списке. Вот измененный вариант скрипта:

#!/bin/bash

# Список процессов, которые нужно завершать
TROUBLEMAKERS="vlc opensnap glxgears stress"

# Установка предела загрузки CPU
CPU_USAGE_LIMIT=90

# Получение информации о процессе с самой высокой загрузкой CPU
TOPPROCESS=$(ps -eo %cpu,pid,comm --sort=-%cpu | sed -n '2p')
TOPCPU=$(echo "$TOPPROCESS" | awk '{print $1}')
TOPPID=$(echo "$TOPPROCESS" | awk '{print $2}')
TOPNAME=$(echo "$TOPPROCESS" | awk '{print $3}')

if (( $(echo "$TOPCPU > $CPU_USAGE_LIMIT" | bc -l) )); then
    echo "Процесс: $TOPNAME (PID: $TOPPID) использует $TOPCPU% CPU, превышая лимит."
    if [[ "$TROUBLEMAKERS" == *"$TOPNAME"* ]]; then
        kill -9 $TOPPID
        echo "Процесс $TOPNAME с PID $TOPPID был завершен."
    else
        echo "$TOPNAME не входит в список проблемных процессов. Завершение отменено."
    fi
else
    echo "На данный момент нет процессов с загрузкой выше $CPU_USAGE_LIMIT%."
fi

5. Использование утилит pgrep и pkill

Если вы знаете группы процессов, которые вероятно могут использовать высокий CPU, вы можете использовать pgrep и pkill для завершения всех процессов с определенным именем, например:

pkill -f "имя_процесса"

Заключение

Создание автоматического механизма для завершения процессов с высокой загрузкой CPU может существенно улучшить производительность вашей системы. Настраивая параметры и добавляя специфические условия для нужд вашей системы, вы можете более эффективно управлять ресурсами.

Оцените материал
Добавить комментарий

Капча загружается...