Featured image of post Linux基础(八):进程管理

Linux基础(八):进程管理

进程结构、进程状态、ps aux/top、僵尸进程、孤儿进程、信号

储备知识

同步与异步:任务的启动/调用方式

程序:存放代码的文件=》静态
进程:程序的运行过程=》动态

  • 同步: 多个任务是同步执行的指的是启动一个任务之后,必须在原地等待该任务运行完毕之后,才能启动下一个任务并且运行

  • 异步: 提交完一个任务之后,不用在原地等待该任务运行完毕 就能立即提交下一个任务执行

补充&符号: &作用:在bash命令后加&符号,可以把该命令放到后台运行

并发与并行:指的是任务给人展现出的运行的效果

并发/并行:多个任务是”同时“运行的

串行:一个任务运行完毕,才能运行下一个

阻塞与非阻塞:任务在操作系统中的运行状态

会引起阻塞的事项: 1、硬盘io 2、网络io 3、sleep 4、read命令

进程的结构:树形结构

0 号:整个系统的祖宗进程

0号进程会产生两个进程1号和2号

  • 1号:是所有用户态进程的祖宗
  • 2号:是所有内核态进程的祖宗

进程的状态(R、S、D、T、Z、X)

活着的

  1. 运行、就绪着的 R
    • 正在执行:手里拿着cpu正在运行
    • 就绪(随时可以投入运行):正在等待操作系统分配cpu,一旦分配到,就可以立即投入运行
  2. 阻塞着的 S 或 D
    • S:可中断的睡眠
      • 可以用例如ctrl+c, kill -9 pid号命令来终止
    • D: 不可中断睡眠(因为存储设备太忙了响应不过来了)
      • 不可以被中止(linux系统为了防止数据丢失的一种保护机制)

死了的

  1. 僵尸进程 Z 僵尸进程是操作系统的一种优化机制 一个进程死掉之后,会把其占用的 cpu、内存资源都释放掉,但是会保留该进程的状态信息 例如 pid 号、存在过的一些运行信息 这些保留下来的信息都是操作系统给父进程准备的 每个进程死掉之前都会进入僵尸进程的状态 僵尸进程通常由父进程来回收
  2. 退出的进程 X 进程已完全终止,仅在内核态短暂出现。 用户态工具(如 ps)通常看不到此状态。

补充: +号:前台运行的进程 s:表示该进程是会话(session)的领导/领导进程,用来接收用户请求,然后自己不干给儿子进程去干 l:当前进程是多线程模式 <: 高优先级的进程 T:暂停

给进程发送一个SIGSTOP信号,进程就会响应信号进入T状态, 再通过发送SIGCONT信号让进程继续运行。 kill -SIGSTOP pid号 kill -SIGCONT pid号

ps aux 命令解析

1
2
3
4
5
6
[root@localhost ~]# ps aux |head -5
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.0  0.3 128400  7104 ?        Ss   8月12   0:05 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root          2  0.0  0.0      0     0 ?        S    8月12   0:00 [kthreadd]
root          4  0.0  0.0      0     0 ?        S<   8月12   0:00 [kworker/0:0H]
root          5  0.0  0.0      0     0 ?        S    8月12   0:01 [kworker/u256:0]

USER: 运行进程的用户

PID: 进程ID

%CPU: CPU占用率

%MEM: 内存占用率,指的是实际内存RSS占用率

VSZ: 占用虚拟内存,单位:KB(killo Bytes) VSZ是指已分配的线性空间大小,这个大小通常并不等于程序实际用到的内存大小,产生这个的可能性很多 比如内存映射,共享的动态库,或者向系统申请了更多的堆,都会扩展线性空间大小。

RSS: 占用实际内存,单位:KB(killo Bytes) RSZ是Resident Set Size,常驻内存大小,即进程实际占用的物理内存大小

TTY: 进程运行的终端

STAT: 进程状态 man ps (/STATE)
R 运行 S 可中断睡眠 Sleep,即在睡眠的过程中可以接收信号唤醒=》执行的IO操作可以得到硬件设备的响应 D 不可中断睡眠,即在睡眠的过程中不可以接收信号唤醒=》执行的IO操作得不到硬件设备的响应 T 停止的进程 Z 僵尸进程 X 死掉的进程(几乎看不见,因为死了就立即回收了)

< 标注了<小于号代表优先级较高的进程 N N代表优先级较低的进程

s 该进程包含子进程,该进程自己是整个会话的领导者

  +     +表示是前台的进程组

  l     小写字母l,代表以线程的方式运行,即多线程
  |     管道符号代表多进程

START: 进程的启动时间 TIME: 进程占用CPU的总时间

COMMAND: 进程文件,进程名 带[]号的代表内核态进程 不带[]号的代表用户态进程 补充Centos9中还有一个大写字母I的进程状态 大写字母"I"代表的进程状态是"Idle kernel thread",这意味着该进程是一个空闲的内核线程,不是用户模式下的空闲进程。这个状态通常只应用于内核线程,用户进程通常不会有这个状态。

VSZ 虚拟内存与 RSS 物理内存

  1. VSZ(Virtual Memory Size)
  • 含义:进程可访问的全部内存(包括实际占用+预留的共享库/映射文件)。
  • 特点:
    • 包含未实际使用的内存(如申请但未写入的堆空间)。
    • 单位通常为 KB(ps aux 中显示的值)。
  • 示例:
    若进程申请 1GB 堆但仅写入 100MB,VSZ ≈ 1GB。
  1. RSS(Resident Set Size)
  • 含义:进程实际占用的物理内存(不含交换分区 Swap)。
  • 特点:
    • 包含共享库中已被加载的部分。
    • 直接反映进程对物理内存的压力。
  • 示例:
    上述进程中,RSS ≈ 100MB(实际写入的物理内存)。

pstree 查看进程树

top 命令解析

基本用法

1
2
3
4
5
6
7
[root@localhost ~]# top
[root@localhost ~]# top -d 1  # 1秒刷新一次
[root@localhost ~]# top -d 1 -p 进程的pid
[root@localhost ~]# top -d 1 -p `pgrep nginx | head -1`
[root@localhost ~]# top -d 1 -p `pgrep sshd | head -1`,33  # 查看sshd以及pid为33的进程
[root@localhost ~]# top -d 1 -u nginx  # 查看指定用户进程
[root@localhost ~]# top -b -n 2 > top.txt  # 将2次top信息写入到文件

显示信息解释

  • 第1行(系统状态):
    top - 15:30:02 up 10 days, 3 users, load average: 0.5, 0.3, 0.2
    • 15:30:02:当前时间
    • up 10 days:系统运行时间
    • load average:1/5/15分钟的平均负载(核心数≤1为正常)。
  • 第2行(任务统计):
    Tasks: 100 total, 2 running, 98 sleeping, 0 stopped, 0 zombie
    • running:运行中的进程数
    • zombie:僵尸进程数(需警惕)。
  • 第3行(CPU使用率):
    %Cpu(s): 5.3 us, 2.0 sy, 0.0 ni, 92.7 id, 0.0 wa, 0.0 hi, 0.0 si
    • us:用户态CPU
    • sy:内核态CPU
    • niNice Time 低优先级进程(Nice 值 > 0)占用的 CPU 时间百分比
    • wa:I/O等待(高则磁盘瓶颈)
    • id:空闲CPU。
    • hi:Hardware Interrupt Time 硬件中断占用 CPU(如键盘/磁盘)占用的 CPU 时间百分比
    • si:Software Interrupt Time 软中断处理占用 CPU(网络、多核任务调度)占用的 CPU 时间百分比
  • 第4行(物理内存):
    MiB Mem : 8000 total, 200 free, 5000 used, 2800 buff/cache
    • used:已用内存(含缓存)
    • free:完全空闲内存。
  • 第5行(交换分区):
    MiB Swap: 2000 total, 1500 free, 500 used
    • used:Swap使用量(高则物理内存不足)。

交互快捷键

  • P:按CPU%排序
  • M:按内存%排序
  • k:终止进程(输入PID)
  • q:退出
  • 1:展开多核CPU详情

average 平均负载(负载指的是几个活跃的活要干):在一段时间内,处于 R 状态的进程数+不可中断 D 睡眠的进程数 平均负载是用来要衡量系统的繁忙程度 4 个 cpu: 平均负载为 3,代有个 3 个活跃进程,—》低负载 平均负载为 4,代有个 4 个活跃进程,—》满负载 平均负载>4, —》超负载 cpu 的利用率:反应的是 cpu 的使用情况

特殊进程

僵尸进程、孤儿进程

僵尸进程:进程已终止,但其退出状态未被父进程回收(残留内核中的 task_struct)。

  • 状态码 Z
  • 产生原因:
    • 父进程未调用 wait()waitpid()
    • 父进程异常退出(如被 kill -9)。
  • 影响:
    • 占用 PID(可能导致 PID 耗尽)。
    • 不消耗 CPU/内存。
  • 解决:
    • 终止父进程(内核会回收其所有僵尸子进程)。
    • 重启服务或系统。

孤儿进程:父进程已终止,子进程被 init(PID 1)接 管。

  • 状态码:正常( SR
  • 产生原因:
    • 父进程主动/被动退出(如崩溃)。
    • 子进程仍在运行。
  • 影响:
    • 无害,init 会负责回收资源。
    • 可能长期运行(如后台服务)。
  • 用途:
    • 实现守护进程(如 nginxsshd

守护进程

Daemon Process 守护进程是 在后台长期运行的特殊进程,脱离终端控制,通常作为系统服务(如 sshdnginx) 以下几点是守护进程的一些主要特征:
1、守护进程在后台运行,通常不需要与用户交互。
2、守护进程通常长时间运行,直到系统关闭。
3、守护进程没有控制终端,也不拥有标准输入设备,标准输出设备或标准错误设备。

守护进程与普通进程的区别主要体现在:
1、生命周期:普通进程通常由用户启动,任务完成后结束;而守护进程在系统启动后自动运行,直到系统关闭。
2、控制:普通进程通常有控制终端,可以直接与用户交互;而守护进程没有控制终端,通常通过系统日志、配置文件等方式进行管理和配置。

管理进程

给进程发信号

kill -l 列出所有支持的信号 最常用的八个信号:

信号编号 信号名 默认行为 典型用途
1 SIGHUP 终止进程 重新加载配置(如 nginx -s reload 发送 SIGHUP 给主进程)
2 SIGINT 终止进程 Ctrl+C 触发,优雅终止前台进程
3 SIGQUIT 终止 + 核心转储 Ctrl+ 触发,用于调试(生成 core 文件)
9 SIGKILL 强制终止 立即杀死进程(不可被捕获/忽略),救急用
15 SIGTERM 终止进程 默认信号,允许进程清理资源(如 kill <PID>
18 SIGCONT 继续运行 恢复被 SIGSTOP 暂停的进程(如 kill -18 <PID>
19 SIGSTOP 暂停进程 立即暂停进程(不可被捕获/忽略),Ctrl+Z 触发
20 SIGTSTP 暂停进程 可被捕获的暂停(如 Ctrl+Z 时程序可先执行清理)

kill -15杀死进程(该信号可以被捕获、忽略和阻塞,有时候会被进程捕获然后忽略导致无法终止,则需要用-9)

杀死所有:根据进程名杀所有

killall -9 vim pkill -9 vim

HUP 信号

HUP信号,主要涉及两种应用场景: 1、终端关闭时,系统会向与该终端相连的所有进程发送SIGHUP信号,这会导致这些进程被关闭(所有才有了脱离终端运行的需求) 2、用kill命令给进程发送SIGHUP信号实现该进程的平滑重启 需要注意的是,并非所有的进程或应用都能处理SIGHUP信号,只有程序内写过专门的捕获并处理该信号的代码才行, nginx的源代码里就写了,并且会响应该信号来实现平滑重启

脱离终端运行来规避 HUP 信号影响

当用户注销(logout)或者网络断开或者终端关闭,时,终端都会收到Linux HUP信号(hangup)信号,然后终端在结束前会关闭其所有子进程。 注意注意注意,一定是终端整体关闭,不是单纯的exit,就是说你要点击窗口的×号关闭

如果我们想让我们的进程在后台一直运行,不要因为用户注销(logout)或者网络断开或者终端关闭而一起被干掉,那么我们有两种解决方案

  • 方案1:让进程忽略Linux HUP信号
  • 方案2:让进程运行在新的会话里,从而成为不属于此终端的子进程,就不会在当前终端挂掉的情况下一起被带走。

1. nohup 命令

针对方案1,我们可以使用nohup命令,nohup 的用途就是让提交的命令忽略 hangup 信号,该命令通常与&符号一起使用

nohup 的使用是十分方便的,只需在要处理的命令前加上 nohup 即可,但是 nohup 命令会从终端解除进程的关联,进程会丢掉STDOUT,STDERR的链接。标准输出和标准错误缺省会被重定向到 nohup.out 文件中。一般我们可在结尾加上"&“来将命令同时放入后台运行,也可用”>filename 2>&1"来更改缺省的重定向文件名。

2. setsid命令

针对方案1,我们还可以用setsid命令实现,原理与3.1是一样的,setid是直接将进程的父pid设置成1,即让运行的进程归属于init的子进程,那么除非init结束,该子进程才会结束,当前进程所在的终端结束后并不会影响进程的运行

1
2
3
4
5
6
7
8
# 1、在终端2中执行命令
[root@localhost ~]# setsid ping www.baidu.com  # 也可以在后面加&符号
 
# 2、关闭终端2
 
# 3、在终端1中查看
[root@localhost ~]# ps -ef |grep [p]ing
root     102335      1  0 17:53 ?        00:00:00 ping www.baidu.com

3. 在子shell中提交任务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 1、在终端2中执行命令
[root@localhost ~]# (ping www.baidu.com &)  # 提交的作业并不在作业列表中
 
# 2、关闭终端2
 
# 3、在终端1中查看
[root@localhost ~]# ps -ef |grep [p]ing
root     102361      1  0 17:55 ?        00:00:00 ping www.baidu.com
 
可以看到新提交的进程的父 ID(PPID)为1(init 进程的 PID),并不是当前终端的进程 ID。因此并不属于当前终端的子进程,从而也就不会受到当前终端的Linux HUP信号的影响了。
使用 Hugo 构建
主题 StackJimmy 设计