有时程序会在后台锁定并导致 CPU 使用率过高。有什么方法可以以编程方式确定当前哪个进程导致 CPU 负载最高并杀死它?
答案1
有一系列 Unix 命令,如果您了解它们适合此类工作,它们可能会更好地为您服务。
- 正则表达式
- 删除
- 全杀
您可以使用这些工具使您的“攻击”更有针对性,尤其是在您知道行为不当进程的名称的情况下。
全杀
我的 Chrome 经常出现一个问题,最终需要通过杀死它来解决。我通常会执行此命令来消灭所有它们。
$ killall chrome
pgrep 和 pkill
但我也可以这样做,只处理最新的进程:
# to list
$ pgrep -n chrome
23108
# to kill
$ 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 shellARGV0设置为这些名称。顺便说一句,我使用这个技巧进行了这些过程:
$ (exec -a "some weird command name's friend" bash)
去追朋友
但是假设我有很多这样的人,我只想追踪其中的一组特定人,因为他们的命令行中有“朋友”。我可以这样做:
$ 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
列出使用逗号 ( ,
) 分隔的进程 ID:
$ 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 进程。您可以使用以下方法进行杀死:
# newest guys
$ pkill -nf vlc ; pkill -nf opensnap
# kill all of these
$ 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
.这样做将返回进程 ID,如下所示:
$ pgrep -f "weird.*friend" -d\|
26673|26911
然后,我们将它们插入到命令中,以便我们可以根据某些进程 IDgrep -E ...
过滤输出。top
这看起来似乎有很大的后退,但我们现在可以肯定地知道,我们使用的进程 ID 只是与名为“weird.*friend”的给定进程相关的进程 ID。
从这里你可以找到 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
),这将是“weird.*friend”进程中 CPU 最高的进程。
答案2
可以设置“和”程序 Auto-Nice Daemon 来执行此操作。
您设置了一个列表,其中包含几个特定的已知麻烦制造者和三个重新处理级别(以便您可以逐渐严厉地重新处理),但其中任何一个都可能已经杀死了该进程,尽管这通常会被保留为最后一招。
调节事物以达到特定所需的 CPU 负载水平并不总是那么容易,但还有其他工具可能会有所帮助(并通过防止攻击来帮助避免杀死有问题的进程),例如 cpulimit,并且已经开始带有 Nice 和 ionice 的程序。
答案3
编辑脚本
@msw、@sim 和其他用户对我的脚本的概念提出了合理的担忧。受到 @sim 的回答和 msw 的评论的启发,我坐下来重新思考如何解决我的特定问题(几个已知的进程时不时地造成麻烦)。这是我想出的:
#!/bin/bash
# tries to kill process with highest CPU load
# (if it is part of a specified list of troublemakers)
TROUBLEMAKERS="vlc opensnap glxgears stress"
sleep 1 # wait a few seconds (just as a precaution)
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 "Cause of high CPU load: "$TOPNAME" ("$TOPPID")"
echo "In troublemaker list. Killing..."
kill -9 $TOPPID
else
echo "Cause of high CPU load: "$TOPNAME" ("$TOPPID")"
echo "Not in troublemaker list. Exiting..."
exit 1
fi
exit 0
与前一个脚本相反,如果 CPU 负载最高的进程的名称与许多已知的麻烦制造者(容易锁定系统的进程)匹配,则该脚本只会杀死该进程。
原创剧本
这是一个简单的脚本,它将确定导致系统上最高瞬时 CPU 负载的进程并杀死它(Xorg 除外,它会导致 GUI 崩溃):
#!/bin/bash
# tries to kill process with highest CPU load
# (if it isn't Xorg)
sleep 1 # wait a few seconds (just as a precaution)
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 load caused by Xorg. Exiting."
exit 1
fi
exit 0
该TOPPROCESS
片段基于这个条目在 commandlinefu.com。
答案4
#!/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 "Does not exist"
fi