文章目录
Linux 就像玩游戏,我要 double kill ......
0. 前言
时常在深夜写代码,耳边萦绕着键盘的轻敲声和电脑风扇的低吟声。昏暗的电脑屏幕照亮了周围的空间,一个舒适而亲密的空间。窗外的夜空清晰明亮,星星闪烁着像小钻石一样。感觉外面的世界已经消失了,只留下了我和我的代码。时间像流水,渐渐流逝;代码如火车,慢慢跑起。随着代码奔跑带动的风扇旋转声越来越大,鼠标和键盘的输入在屏幕上逐渐变卡,直到所有IO都定格在某个隐秘的位置…我意识到:死机了,进程卡死了!
好了,这段充满意境的开场白其实是大语言模型为我们提供的,目的就是引出本文的主角:进程。
迄今为止,进程管理一直都是绝大多数OS逃不开的话题,是几乎每个OS都要提供的基础功能,Linux也不例外。
本文将要介绍的是 Linux 中常见的进程管理。下面我们开始!
学习目标
- 学习 Linux 中 进程管理相关的命令
- 会使用相关命令,对自己或服务器的Linux作进程管理
参考教程
- 《Linux命令行大全》—— William E.Shotts, Jr.
- Linux命令大全在线手册:https://www.linuxcool.com/
1. 查看进程
现代操作系统通常都支持多重任务处理,系统通过快速切换运行中的程序,使得用户在宏观上的感受是多个任务同时执行。随着硬件的发展,一些计算机也可以通过并行的方式实现多个任务同时进行,但最终也离不开进程管理。Linux内核通常使用进程来控制多重任务。
本文开头提到的死机现象,就是应用程序停止响应,或者由于进程冲突等因素,触发了操作系统的中断程序,导致整个计算机中断。有时,我们的进程还不至于使操作系统触发中断机制,只是计算机的运算速度变得很慢,这时候,我们使用进程管理就很必要了。
在图形化操作的操作系统,例如我们用得最多的Windows,一般来说出现卡了的现象,我们就打开应用管理器,把一些不必要的进程杀掉,或者手动退出各种应用程序即可。
那么在Linux命令行,我们如何控制进程呢?
在控制进程之前,我们首先要学会查看进程。GUI查看进程的方式非常直观,Linux也提供了一些命令供用户查看进程。
1.0 Linux 进程工作
在正式学习命令之前,我们先来了解一下在Linux中,进程是如何工作的。
Linux系统启动时,内核先把它的一些程序初始化为进程,然后运行一个名为init
的程序(即初始化的简称)。init
程序将依次运行一系列的初始化shell
脚本(init script,于 /etc 目录下)。这些脚本会启动所有的系统服务。其中,许多服务是通过守护程序(daemon program)实现的。
一个程序的运行可以出发其他程序的运行,即父进程创建子进程。
Linux内核会保存每个进程的信息以便确保任务有序进行。每个进程会被分配一个ID,其中,init
的 ID 始终为1。Linux 内核同时记录分配给每个进程的内存信息以及用来恢复运行的进程就绪信息。
继承自UNIX一切接文件的思想,进程在系统中也和文件类似,也存在所有者、用户ID等等信息。
接下来的小节中,我们将接触到这些信息。为了方便一些操作与演示,本文将用Ubuntu系统来进行实操演示。
1.1 ps 显示当前所有进程
唠了这么久,我们终于开始了本文的实操环节了。首先要介绍的的ps
命令,用于查看进程信息。
举例
sharry@sharry-virtual-machine:~/Desktop$ ps
PID TTY TIME CMD
52560 pts/0 00:00:00 bash
52758 pts/0 00:00:00 ps
不带选项的ps,只输出了当前终端会话相关的进程信息。其中,这个例子输出了ID、终端、消耗的CPU时间总和,以及进程名。
我们带一些选项试试吧:
sharry@sharry-virtual-machine:~/Desktop$ ps -x
PID TTY STAT TIME COMMAND
1904 ? Ss 0:02 /lib/systemd/systemd --user
1906 ? S 0:00 (sd-pam)
1912 ? S<sl 0:00 /usr/bin/pipewire
1913 ? Ssl 0:00 /usr/bin/pipewire-media-session
1914 ? S<sl 0:01 /usr/bin/pulseaudio --daemonize=no --log-target=journal
1924 ? Ss 0:03 /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
1926 ? Sl 0:00 /usr/bin/gnome-keyring-daemon --daemonize --login
1934 ? Ssl 0:00 /usr/libexec/gvfsd
1941 ? Sl 0:00 /usr/libexec/gvfsd-fuse /run/user/1000/gvfs -f
1954 ? Ssl 0:00 /usr/libexec/xdg-document-portal
结果太长,此处选取了一部分粘贴在这里,读者有空可自己多尝试。
-x
选项表示ps
所有进程,而不需要关注它们是哪个终端的,因此TTY
列显示的问号?
表示没有控制终端; STAT
表示进程运行状态,常见的状态有:
- R 运行状态
- S 睡眠状态
- D 不可中断的睡眠状态
- T 暂停状态
- Z 僵尸进程
- < 高优先级进程
- N 低优先级进程
更详细的信息读者可多查阅相关文档以获取更深一步了解。
前面我们提到过 进程还有 用户ID 等更多信息,因此ps
也提供了 -aux
选项来获取更多信息:
sharry@sharry-virtual-machine:~/Desktop$ ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.1 0.2 168072 9908 ? Ss 18:59 0:13 /sbin/init auto noprompt splash
root 2 0.0 0.0 0 0 ? S 18:59 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? I< 18:59 0:00 [rcu_gp]
root 4 0.0 0.0 0 0 ? I< 18:59 0:00 [rcu_par_gp]
root 5 0.0 0.0 0 0 ? I< 18:59 0:00 [slub_flushwq]
其中,一些列的含义显而易见,这里补充几个列的说明:
- %MEN 使用内存百分比
- VSZ 虚拟耗用内存大小
- RSS 实际使用内存大小
1.2 top 实况显示任务
top
显示的实况任务,运行top
命令后,会进入top
,然后实时刷新各进程的信息
一般情况下,我们要退出top
按 q 即可。
1.3 jobs 列出活动作业信息
为了方便截图与演示,本文小编用了一台Ubuntu虚拟机,这台Ubuntu尚未配置关闭GUI最小化运行,因此保留了图形化界面。我们首先运行xlogo程序来看看图形化效果吧:
然后,我们执行jobs
查看通过终端启动的进程信息:
sharry@sharry-virtual-machine:~/Desktop$ jobs
[1]+ Running xlogo &
返回了运行状态及是否为后台运行,&
表示在后台运行。关于进程的&
,将在下面章节介绍。
2. 控制进程
最鸡动人心的章节来啦,本章介绍包括kill
在内的进程控制方式。
2.1关机与重启
通常,关机或重启能解决98%的问题,这是因为当进程由于某些原因卡死时,通过OS关机或重启的操作,可以在操作系统层面杀死卡死的进程,并由操作系统的备份策略,当重启时,保留一部分运行信息,并可由该进程的设定决定是否接着运行下去。
关机
shutdown [选项] [其它信息]
选项与参数说明:
-c:#执行shutdown命令后,只需要按+键就可以中断正在执行的命令
-f:#重启时不执行fsck
-F:#重启时执行fsck
-h:#关机
-k:#发送信息给所有用户,但不会关机
-n:#不调用init程序进行关机
-r:#关机之后再重新启动
-t<秒数>:#发送警告信息和删除信息之间的延迟时间
重启
reboot [选项]
选项说明:
-n : 在重开机前不做将记忆体资料写回硬盘的动作
-w : 并不会真的重开机,只是把记录写到 /var/log/wtmp 档案里
-d : 不把记录写到 /var/log/wtmp 档案里(-n 这个参数包含了 -d)
-f : 强迫重开机,不呼叫 shutdown 这个指令
-i : 在重开机之前先把所有网络相关的装置先停止
注:以上 shutdown
及 reboot
命令的说明,节选自INFQ
社区 以及 BootWiki
2.2 bg、& 设置后台作业
前面我们已使用过 &
让xlogo程序在后台运行,当我们不加&
时,我们会发现,无法再在当前terminal
执行其他命令,除非ctrl + c
终止该进程,读者可以试试。
& 后台运行并返回进程号
我们拿 cat 命令来试试:
sharry@sharry-virtual-machine:~/Desktop$ cat &
[2] 53349
bg 将进程放到后台作业
我们用经典的 sleep
命令来测试 这个命令的效果:
sharry@sharry-virtual-machine:~/Desktop$ sleep 400
^Z
[2]+ Stopped sleep 400
sharry@sharry-virtual-machine:~/Desktop$ bg %2
[2]+ sleep 400 &
由上述例子可见,当我们暂停了sleep
命令后,再使用bg + [序列号]
的方式可以将进程放到后台作业,执行bg
命令后,标准输出返回了bg
命令的执行信息:当前终端进程序列号 命令 及后台运行&
2.3 fg 设置前台作业
fg
的使用与bg
相似,作用相反。我们直接举例子:
将cat
先放入后台运行,再用fg
放到前台运行:
sharry@sharry-virtual-machine:~/Desktop$ cat
^Z
[1]+ Stopped cat
sharry@sharry-virtual-machine:~/Desktop$ bg %1
[1]+ cat &
sharry@sharry-virtual-machine:~/Desktop$ fg %1
cat
hahaha
hahaha
2.4 kill 杀死进程
我们常用kill
命令来执行杀死进程的操作,也是最常用的kill
操作之一。例如:
sharry@sharry-virtual-machine:~/Desktop$ xlogo &
[1] 55887
sharry@sharry-virtual-machine:~/Desktop$ kill 55887
sharry@sharry-virtual-machine:~/Desktop$ ps
PID TTY TIME CMD
55866 pts/0 00:00:00 bash
55888 pts/0 00:00:00 ps
[1]+ Terminated xlogo
其实,kill
的作用还有很多,不仅仅是杀掉进程,kill
一般情况下,kill
命令的格式为:
kill [-信号选项] 进程号
当我们不选择代表信号的选项时,默认是杀死进程。
常见的进程信号有:
- HUP 挂起
- INT 中断信号,和键盘执行
ctrl + c
的效果一致 - KILL 强杀死信号。我们知道,一般情况下我们杀死一个进程,实际上执行的是进程中断,进程中断后,再交给内核对该进程作剩下的处理,例如清理或对当前工作保存。而KILL信号,则是强行将该进程教友内核终止。一般情况下,KILL是一个兜底的选项
- TERM 终止进程,即杀死进程,当我们不选择代表信号的选项时,默认向进程发送的信号就是这个TERM
- STOP 暂停,仅仅是暂停一下进程而已
- CONT 对暂停的进程恢复运行
我们稍微举个例子:
sharry@sharry-virtual-machine:~/Desktop$ xlogo &
[1] 79605
sharry@sharry-virtual-machine:~/Desktop$ jobs
[1]+ Running xlogo &
sharry@sharry-virtual-machine:~/Desktop$ kill -STOP 79605
sharry@sharry-virtual-machine:~/Desktop$ jobs
[1]+ Stopped xlogo
sharry@sharry-virtual-machine:~/Desktop$
sharry@sharry-virtual-machine:~/Desktop$ kill -CONT %1
sharry@sharry-virtual-machine:~/Desktop$ jobs
[1]+ Running xlogo &
sharry@sharry-virtual-machine:~/Desktop$
kill
的信号选项还有很多,如 -QUIT
退出信号等等,读者可以用到的时候再去查阅文档,以决定最适合的kill
选项。
2.5 killall 杀死多个进程
有了上一小节的基础,killall
就很好理解了,它就像是对kill
命令的一个拓展,可以一次性向多个进程发送信号,如果有Root 用户权限,还能向普通用户的进程发送信号,格式如下:
killall [-u user] [-signal] name
注意,这里的name
直接就是进程名字,可以直接向所有同名进程发送信号。
sharry@sharry-virtual-machine:~/Desktop$ xlogo &
[2] 79842
sharry@sharry-virtual-machine:~/Desktop$ xlogo &
[3] 79843
sharry@sharry-virtual-machine:~/Desktop$ jobs
[1] Running xlogo &
[2]- Running xlogo &
[3]+ Running xlogo &
sharry@sharry-virtual-machine:~/Desktop$ killall xlogo
[1] Terminated xlogo
[2]- Terminated xlogo
[3]+ Terminated xlogo
sharry@sharry-virtual-machine:~/Desktop$ jobs
sharry@sharry-virtual-machine:~/Desktop$
3. 总结与补充
除了用命令行,我们还可以通过键盘停止当前运行,例如,经典的ctrl + c
,或者执行一些指令让程序满足终止条件,例如cat 的 ctrl + d
等等。当然这在前面以及其他一些参考资料也提到过,有趣的是,ctrl + c
在其他OS 的一些终端也适用,就像Windows的powershell。
另外,要暂停一个在前台运行的进程,我们可以用ctrl + z
。
键盘信号
为什么我们按下ctrl + c
时,进程就终止了呢?这是因为,当终端接收到我们键盘的输入时,它将发送信号到前台进程。当我们按下的是ctrl + c
时,它将发送一个称为TSTP(Terminal Stop)的信号,这个信号的原理与kill
命令发送信号是类似的。同时,进程也会监听到信号并按照信号的指示进行下一步的操作。
最后,我们总结一下:本文首先介绍了Linux下进程的运行方式,再介绍了查看进程信息的方式:ps、jobs等,最后,我们介绍了进程控制方式,包括将进程设置为后台、前台运行、kill 杀死进程 或向进程发送信号量等。
下次再遇到Linux系统慢、卡,解决的手段又多了。