目录
那天开会的时候,发现孟哥的电脑风扇一直在高速旋转,而且看他分享屏幕的时候,编辑在线文档卡到飞起,撇了一眼协助编辑的人也不是很多,而且这个项目才刚刚开始,这么卡,我猜老孟这电脑怕不是这一周都没休息过,里面堆积了很多进程。也难怪,老孟平时忙的要命,有时候弄东西弄到一半就被喊去开会或者要忙别的事,哪来时间打理电脑。现在打开他的电脑任务管理器,估计内存已经爆了,被进程占满了。说到这就想到,好像还没有写过关于Linux系统进程的博客,索性和大家分享分享,自己也学习学习。
1. 系统进程
1.1 什么是进程
既然要学习如何管理进程,那么我们首先要知道什么是进程。
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配的基本单位,是操作系统结构的基础,进程是程序的实体,是对运行中的程序的抽象(此词条解释来源百度)。
开发人员通过编写代码,将他们打包起来组成一个程序,当我们打开一个程序的时候,系统内核便会为它分配资源,每个进程都有系统给他分配的地址空间和cpu时间(cpu在处理这个进程上花的时间),用易理解的话来说,程序是“死”的,处理器赋予它生命,它就“活”了,进程其实就是执行中的程序。
知道了什么是进程,我们便可以继续铺开来说线程,线程是操作系统能够运算调度的最小单位,它被包含在进程之中,一个进程可以有多个线程,执行不同的任务,多个线程共享进程的全部资源。比如我们平时使用微信或者QQ聊天,打开了多个会话窗口,进程就将它分为多个线程放在多核处理器当中并行操作,避免了一个处理器在线程之间来回切换。
当然,线程和子进程是不一样的,每个子进程处于独立的空间,不共享进程的全部资源,就拿我们的浏览器来说,我们打开了Microsoft Edge,这时候浏览器会由程序变为进程,有一个主进程,负责管理所有窗口和标签页,处理用户界面、网络请求等。然后我们打开很多额外的标签页,这些标签页就属于浏览器的子进程,这些子进程互不干扰,假如我看b站,卡死了,但是我旁边的百度照样搜东西(除非主进程卡死了),浏览器正常运行。
但是,换成线程就不行了,比如你在打lol,进程分为多线程来处理任务,比如图形渲染、游戏逻辑计算、声音处理、玩家输入等,假如图形渲染这个线程挂了,那你肯定是玩不了了,而且整个游戏就会报错,所以现在开发者都会设计异常处理机制,捕获处理一些线程异常,所以有的时候会出现一些bug(指进程方面的bug),但不会整体崩溃。
1.2 进程管理命令
知道了什么是进程之后,我们要学会如何管理系统中的进程,在Linux操作系统中,我们可以通过这些常用的命令来实现对进程的查看、监测与管理。
1.2.1 ps命令
ps命令用于显示当前运行进程的状态信息
常用的参数
-a:显示当前终端下的所有进程信息,包括其他用户的进程。与“x”选项结合时将显示系统中所有的进程信息。
-u:使用以用户为主的格式输出进程信息。
-x:显示当前用户在所有终端下的进程信息。
ps命令通常不会使用一个单独的参数,一般直接用 ps -aux 组合使用来显示系统上所有正在运行的进程的详细信息
上述输出信息中,第一行为列表标题,其中各字段的含义描述如下
USER:运行该进程的用户名
PID:进程的唯一标识符,进程ID
%CPU:CPU占用的百分比。
%MEM:内存占用的百分比。
VSZ:该进程使用的虚拟内存量(KB)。
RSS:该进程占用的物理内存量(KB)。
TTY:表明该进程在哪个终端上运行。不是从终端启动的进程则显示为?。
STAT:该进程的状态(包括 :D:不可中断的休眠状态:R:正在运行状态;S:处于休眠状态,可被唤醒;T:停止状态,可能是在后台暂停或进程处于跟踪调试状态: Z:僵尸进程,进程已经中止,但是部分程序还在内存当中)
START:启动该进程的时间。
TIME:进程已经消耗CPU的时间
COMMAND:启动进程的命令名称和参数
STAT(进程状态)那一列,有些进程后面还有字符,这些字符表示:
<: 表示进程运行在高优先级上
N: 表示进程运行在低优先级上
L: 表示进程有页面锁定在内存中
s: 表示进程是控制进程
l: 表示进程是多线程的
+: 表示当前进程运行在前台(这里有前台那肯定有后台,在命令后面加上&可以将操作直接放至后台,如后台复制光盘镜像可以用cp /dev/cdrom /home/cetos7.iso &)
D:系统守护进程
下面我们来尝试改变一个进程的状态,并查看验证。
首先我们双击连接,重新打开一个终端,称为终端ZDB,在此终端vim a.txt 编辑一个文件
这时候我们回到第一个终端,下面称为ZDA,然后我们输入
ps -aux | grep a.txt 查看a.txt 的进程状态
现在我们回到ZDB然后按ctrl z 停止,这时候在ZDA再次输入ps -aux | grep a.txt
我们可以看到
这里解释一下 ctrl c 是发送 SIGINT 中断信号,通常会导致程序停止运行并返回到命令提示符; ctrl z 是发送 SIGSTOP 信号,挂起一个正在前台运行的进程,将作业放置到后台(暂停) ;ctrl d ,代表告诉终端,输入已经完成或者注销当前会话。
所以在系统出现问题时,我们可以用ps -aux快速查看当前正在运行的进程,帮助确定是否有异常进程或者占用资源过多的进程。
除了ps -aux还有ps -elf ,这个命令的意思是以长格式显示系统中的进程信息,包含了更多字段
这里出现了一些和 -aux不太一样的字符,它们的含义是
F:内核分配给进程的系统标记
S:进程的状态
PPID:父进程的进程号(如果没有明确的父进程,那么一般就是init进程,PID为1)
C:CPU使用的累计时间
PRI:进程的优先级(越大的数字代表越低的优先级)
NI: 优先级的调整值
ADDR:进程的内存地址
SZ:假如进程被换出,所需交换空间的大致大小
WCHAN:若该进程在睡眠,则显示睡眠中的系统函数名
STIME:进程启动时的系统时间
CMD:进程的启动命令
所以,ps -elf 命令一般用来查看和管理进程,以及如何通过分析进程信息来优化系统性能
1.2.2 top命令
那万一我想看一看某一个进程,在运行的时候,占用了多少系统资源,总不能一个终端运行,一个终端一直输入命令 ps -aux 吧。
这时候我们就可以使用 top 命令,top命令提供了实时动态更新的进程列表和资源使用情况,可以方便地监控系统当前的状态,而且还提供了一个交互式界面,允许用户根据需求调整进程排序,还可以调整刷新时间,默认为3秒刷新一次。
我们在终端中输入top
可以看到,一堆字符,我们逐个剖析
第一行分别为:
17:42:36 代表当前时间;
up 2:39系统运行时间 ,说明此服务器连续运行两个小时39分钟了;
4 users 当前登录用户数;
load average 系统负载,即任务队列的平均长度;
第二行系统任务(Tasks)信息分别为:
total,总进程数;
running,正在运行的进程数;
sleeping, 休眠的进程数;
stopped,停止的进程数;
zombie,僵尸进程数;
%Cpu(s) 代表CPU 占用信息:us,用户占用;sy,内核占用;ni,优先级调度占用;id,空闲CPU;wa,I/O 等待占用;hi,硬件中断占用;si,软件中断占用;st,虚拟化占用。要了解空闲的 CPU 百分比,主要看%id 部分。
KiB Mem 代表内存占用(Mem)信息:total,总内存空间;free,空闲内存;used,已用内存;buff/cache,物理内存和交换内存的缓冲区总和。
KiB Swap 代表交换空间(Swap)占用:total,总交换空间;free,空闲交换空间;used,已用交换空间;avail Mem,可用物理空间。
VIRT和VSZ 都表示进程占用的虚拟内存大小
RES和RSS 都表示进程实际使用的物理内存大小
SHR:共享内存大小
其他的与ps -aux和ps -elf 命令输出的字段含义差不多
下面我们来进行实验。
首先我们在ZDA执行top
然后我们去ZDB执行 dd if=/dev/zero of=/a.txt count=10 bs=100M
(这里注意不要设置太大,不然系统可能会卡死,进程将内存占满,有的时候远程连接会中断。
这里我们看到,我的磁盘空间还剩2.1G,然后我依然执行了创建20G文件的命令,提示写入错误。这里我们直接去虚拟机终端操作,因为还是存在远程连接都中断的情况的。
可以看到 / 目录已经被塞满爆红了。
使用 rm -rf /a.txt 命令强制删除a.txt
删除后我们查看一下,系统内存仍然不足,需要清理系统缓存和临时文件:
sync
echo 3 > /proc/sys/vm/drop_caches
可以发现,被占用的空间恢复了。
(注:所有操作都是管理员账户执行
然后我们接着上面说,创建了1GB文件后,回到ZDA我们就可以看到dd这个命令的CPU使用率一下子窜上来了,有的虚拟机可能创建的时候分配的cpu比较强,这里可以适当的增大创建的文件。
可能你们在操作的时候眼睛已经贴到屏幕上了也没找到CPU占用率很大的进程,因为我在top界面按了 P 键。因为 top 命令界面中可以通过按键对特定数值进行排序查看
P 按CPU使用率降序排序
M 按内存使用率降序排序
T 按运行时间长短降序排序
N 按进程ID升序排序
R 按照内存大小降序排列
H 按照线程数量降序排列
K 按照优先级降序排列
数字键 1:显示每个内核的 CPU 使用率 (升序)
U:指定显示的用户 (字母顺序)
h:可以获得 top 程序的在线帮助信息
q:键可以正常地退出 top 程序
上面我们提到,默认 3s 刷新一次,在top命令交互界面下按 s 修改刷新时间按空格 :立即刷新,输入数字就是多少秒。
注:若通过 top 排名工具发现某个进程 CPU 占用率非常高,需要终止该进程的运行,可以在 top 操作界面中按 k 键,然后在列表上方将会出现如下提示信息
根据提示输入指定进程的 PID 号并按 Enter 键, 出现二次确认的提示信息,然后继续按Enter 键确认即可终止对应的进程。
1.2.3 pgrep命令
grep命令是用来查找内容包含指定内容的文件,如果发现某文件的内容符合所指定的内容, grep 命令会把含有所需内容的那一行显示出来
所以,我们可以大概的猜测一下,pgrep命令的作用
pgrep 可以根据进程的名称或其他属性来查找并列出匹配的进程ID
pgrep -l:可同时输出对应的进程名以及PID
比如这里我们输入 pgrep -l 1
可以看到,所有进程id或者进程名字中带有数字 1 的进程都被列了出来
-U:选项查询特定用户的进程
-t:选项查询在特定终端运行的进程
1.2.4 pstree命令
现在,假如我们需要查看一些进程之间的关系,主要是他们的父子关系和依赖关系,我们就可以用 pstree 命令,它会以树状结构的形式展示系统中运行的进程及其关系
-p:选项使用时可以同时列出对应的PID号
pstree [选项] [进程ID]
-u:选项可以列出对应的用户名
pstree [选项] [用户名]
-a:选项可以列出完整的命令信息
通常直接用 pstree -aup 组合起来使用,可以查看当前系统所有进程的进程树,包括各进程对应的PID 号、用户名、完整命令等信息。
1.2.5 jobs命令
jobs命令用于查看管理当前前台和后台的进程
用法是直接输入,如果有相应的进程会显示出来
-l:选项可以同时显示该进程对应的进程号
可以用 fg 加上前面的序号 将该进程放至前台
同样的 bg 加上见面的序号 将该进程放至后台
注意是进程前面的序号,不是进程号
+ 代表当前默认的作业
- 代表默认作业下一个作业
1.2.6 kill命令
kill
那么,我们只知道怎么查看,反复的查看,想要关掉这些进程,该怎么做呢?
我们可以使用kill 命令,来杀死进程,用法是
kill [选项] [进程号]
kill -15 请求进程终止(此选项为默认选项)
-1 挂起
-2 中断
-19 停止进程的执行
-18 继续执行已停止的进程
当我们对一些程序进行操作后,发现该进程已经无法响应终止信号,则可以结合“-9” 选项强行终止进程。
kill 3459 尝试正常结束进程
但发现进程并未退出
这时候我们用 kill -9 3549 强制终止目标进程,然后我们再来查看,可以看到进程已经被残忍的杀死了。
killall
然后,当需要结束系统中多个相同名称的进程时,使用 killall 命令将更加方便,效率更高。killall 命令同样也有“-9”选项,用法和kill差不多,但是多了一个字母选项
killall [选项] [进程]
-e:要求进程名称完全吻合
-I :不区分大小写
-v:显示详细输出
字母选项可以和数字选项结合使用,如我们不区分大小写,强制杀死两个 vim 进程
pkill
pkill 命令可以根据进程的名称、运行该进程的用户、进程所在的终端等多种属性终止特定的进程,用法与 killall 命令类似,但选项更加灵活,如
-U :指定用户
-t :指定终端
-e :列出所有被杀死的进程
-n :只杀死最近启动的匹配进程
其他就不一一举例了 --help 可自行查看,pkill命令主要就是用于杀死指定用户或终端的进程。
如,要终止由用户 zhangsan启动的进程,可以执行以下操作。
在终端B上创建用户zhangsan , vim t1 & 后台运行vim
然后我们回到终端 A,
pgrep –l -U "zhangsan" 先查看zhangsan这小子正在后台搞什么
pkill -9 -U "zhangsan" 管他干什么肯定没干好事,直接给他全部禁止
pgrep -l -U "zhangsan" 再查看一下,万一有活着的要补枪。
然后我们回到zhangsan那边,突然
画面变成这样了,什么都操作不了了,我们成功杀死了zhangsan的进程
2. 计划任务
进程都讲了,顺便说一下如何在指定的时候关闭或开启一些进程。
有些时候我们可能在特定的时间进行一些操作,但是好巧不巧,那个时间点我们恰好有事情要处理,但是这个操作又不得不执行,面对这种两难的情况,我们就需要用到计划任务,即在指定的时间让系统进行指定的操作。
2.1 一次性计划任务at
使用at命令设置的计划任务只在指定的时间点执行一次,需要注意的是,计划执行任务的时间、日期必须安排在当前系统的时刻之后, 否则将无法正确设置计划任务。
设置一次性计划任务时,在 at 命令行中依次指定计划执行任务的时间、日期作为参数 (若只指定时间则表示当天的该时间,若只指定日期则表示该日期的当前时间)
at命令的用法过程大概是,
1:at [时间(格式:xx:xx)] [日期(格式:xxxx-yy-dd)]
2:回车后进入带“at>”提示符的任务编辑界面,每行设置一条执行命令,可以依次设置多条语句
3:最后按 Ctrl+D 组合键提交任务。所设置的命令操作将在计划的时间点被依次执行。
下面我们来举个例子实际操作一下。
设置在 2024 年 6 月 27 日的16:35 自动执行以下任务:统计该时间点系统中由 root 用户运行的进程的数量,并将该数值保存到/opt/ps.root 文件中。ps:现在是北京时间2024.6.27 16:32
at 16:23 2024-06-27
at> pgrep -U root | wc -l > /opt/ps.root 任务设置完毕后按Ctrl+D 组合键提交
这时候我们查看ps.root会提示没有这个文件,别着急,让子弹飞一会,待到山花烂漫时,文件就在灯火阑珊处
再看一下,有啦有啦
下班后人先走机器开着再装一会,领导问到就说上厕所去了,然后九点半再关机,也可以用计划任务来操作。
at 21:30
at> shutdown -h now
at> <EOT>
然后ctrl d 提交
对于已经设置但还未执行的计划任务,可以通过 atq 命令进行查询。已执行过的任务将不会再出现在列表中。
若要删除指定编号的计划任务,可以使用 atrm 命令。删除后的任务将不会被执行,并且不会显示在 atq 命令的结果中,已经执行过的任务无法删除,毕竟它都不会显示的...
于是我们发现,删除后在查看就无了,真是个相当伟大的发现
2.2 周期性计划任务crontab
周期性计划任务约等于就是永久性计划任务了,设置周期性计划任务列表主要通过 crontab 命令进行,结合不同的选项可以完成不同的计划任务管理操作,常用的选项如下
-e:编辑计划任务列表。
-u:指定所管理的计划任务属于哪个用户,默认是针对当前用户(自己),一般只有 root 用户有权限使用此选项(用于编辑、删除其他用户的计划任务)。
-l:列表显示计划任务。
-r:删除计划任务列表。
这里特别讲一下周期性计划任务的时间设置,它是有顺序的,按照“分”“时”“日”“月”“周”的顺序依次设置。“*”代表任意值;“-”代表连续区间;“/”可以直接理解为'每',/5 意思是每五天;“,”用来表示不连续的区间。然后
分钟:0-59
小时:0-23
日期:1-31
月份:1-12
星期:0-7 (0 和 7 都表示星期日)
这么说可能有点抽象,好吧不是有点,是非常。但是,你得先大概看一下上面这些代表个啥。
然后我们来用例子讲一下
crontab -e 进入计划任务编辑表 (这个应该不难懂
然后我们来设置一个每天早上7:50自动开启 sshd 服务
50 7 * * * /usr/bin/systemctl start sshd.service
你看,这个时间就是按照“分”“时”“日”“月”“周”的顺序排的,50是分钟,7是小时,就是七点五十,后面“日”“月”“周”都是“*”,说明什么?看看上面刚写的,“*”代表任意值,什么意思?顾名思义啊,就是随便哪天,随便哪一个月,随便周几,那不就是每天吗?
后面那一坨不管,就是代表着启动sshd服务,但是,它加了个路径,这是为什么呢?因各条计划任务在执行时并不需要用户登录,所以计划任务建议使用绝对路径,避免因缺少执行路径而无法执行命令的情况。
另外,在设置非每分都执行的任务时,“分”字段也应该填写一个具体的时间数值,而不要保留为默认的“*”,否则将会在每分钟执行一次计划任务。
下面再来个例子,每隔五天重启一下httpd服务
0 0 */6 * * /usr/bin/systemctl httpd restart
“分”“时”都是0,就是一天的0点0分,*/6就代表,每六天,无论哪一个月或者哪周几。
那如果我想要每周一、周三、周五的下午两点半重启一下httpd服务呢
30 14 * * 1,3,5 /usr/bin/systemctl httpd restart
这个应该不用再解释了吧
我们可以用crontab -l命令来查看用户的计划任务列表
对于 root 用户来说,还可以结合“-u”选项查看其他用户的计划任务,用法和刚才的pgrep差不多,很简单的,
crontab -l -u zhangsan 就可以知道zhangsan这小子肚子里装的什么坏水
crontab -r -u zhangsan 直接删除zhangsan的计划任务,让他中道崩殂