Orange的运维学习日记–Linux 进程管理
文章目录
进程基础
进程的定义与作用
进程是操作系统分配资源和调度执行的最小单位。每当我们运行一个程序,比如 bash、sshd 或者自写的脚本,内核就会在内存中创建一个新的进程,赋予它独立的地址空间、资源和执行上下文
进程使得多个程序能够并发执行,并隔离各自的运行环境,从而保证系统稳定性与安全性
进程组成与环境
一个典型的进程由以下几部分构成:
- 地址空间:包含代码段、数据段、堆和栈
- 所有权与权限:包括用户 ID、组 ID 以及 Capability
- 执行线程:单线程或多线程,由寄存器和程序计数器决定执行位置
- 系统资源:文件描述符、信号处理函数、网络端口等
除此之外,进程还有环境变量集合、当前调度优先级和打开的资源列表,这些都影响着它的行为与性能
生命周期与状态
进程在其一生中会经历一系列状态转换:
- New:刚创建,还未装载执行代码
- Runnable:就绪队列中等待 CPU 调度
- Running:正在 CPU 上执行,分用户态和内核态
- Sleeping:阻塞等待 I/O、计时器或外部事件
- Stopped:收到暂停信号,挂起执行
- Zombie:已终止,但保留退出状态供父进程回收
- Reaped:父进程调用
wait()后彻底销毁

通常你在日常中只会见到 Running、Sleeping、Stopped 和 Zombie 四种状态


进程查看与属性筛选
操作系统中运行的进程数量往往非常多,要快速定位并获取感兴趣的进程信息,就需要借助 ps 工具。
ps 命令概览
ps 命令可以快照式地打印系统当前进程。它既能列出所有进程,也可以针对用户、终端、命令名称等条件进行过滤,同时支持自定义输出列和排序。
ps 常用选项
- 限定范围
-e或ax:列出所有进程-u 用户名:仅显示指定用户的进程-t 终端名:显示指定终端的进程-C 程序名:按命令名称匹配
- 输出格式
-o 列表:自定义列,如pid,ppid,%cpu,cmd-f、-j:全格式或作业型输出axf:以树形结构展示父子关系
- 排序
--sort 字段:默认升序--sort -字段:降序
示例与说明
下面一段对比展示了几种典型场景:
| 场景 | 命令 | 说明 |
|---|---|---|
| 查看所有进程 | ps -e / ps axu |
最基本的全量列表 |
| 树形查看 | ps axf |
用缩进展示父子进程关系 |
| 按 CPU 占用率排序 | ps axu --sort -%cpu |
找出最占资源的进程 |
| 查看特定用户 | ps -u laoma u |
针对 laoma 用户查看 |
| 查看指定终端 | ps -t pts/1 u |
查看终端 pts/1 下的所有进程 |
| 自定义列查看特定 PID | ps -o pid,ppid,%mem,cmd 1159 |
显示 PID=1159 进程的关键信息 |
| 按命令名称过滤 | ps -C sshd -o pid,user,cmd |
查找所有 sshd 进程并显示 PID 与用户 |
使用 head、grep、awk、sort 等工具组合可以进一步挖掘特定条件下的进程
作业控制
在同一个终端里,你既可以同时运行多个程序,也能灵活地暂停、恢复甚至迁移它们的运行状态
前台与后台作业对比
- 前台作业
- 占用当前终端,能读写标准输入
- 捕获 Ctrl+C(SIGINT)和 Ctrl+Z(SIGTSTP)
- 后台作业
- 不占用输入,即使尝试读取也会被挂起
- 终端列(TTY)显示
?
用 & 将命令放到后台执行,shell 马上返回提示符,你可以同时处理其他事情
控制命令与快捷键
| 操作 | 命令或快捷键 | 作用 |
|---|---|---|
| 列出作业 | jobs |
查看当前所有作业及状态 |
| 前台恢复 | fg %n |
将第 n 个作业切换到前台 |
| 后台恢复 | bg %n |
将暂停的第 n 个作业在后台继续运行 |
| 暂停前台作业 | Ctrl+Z | 发送 SIGTSTP |
| 终止前台作业 | Ctrl+C | 发送 SIGINT |
通过这些命令,你可以在一个 shell 会话中高效地管理多个任务
会话保持工具:nohup vs screen
当你远程登录执行长时间任务时,若突然断网或关闭终端,后台作业可能会被 SIGHUP 信号终止。为此,我们有两种主流方案:
- nohup
- 忽略挂断信号(SIGHUP)
- 输出自动重定向到
nohup.out - 用法:
nohup 命令 &
- screen
- 创建可分离的虚拟终端会话
- 即使断开连接,任务仍在会话中运行
- 安装:
yum install -y screen - 启动:
screen - 列表:
screen -ls - 恢复:
screen -r 会话ID
两者各有优缺点:nohup 简单直接,但无法恢复交互;screen 功能更强,但需要额外学习会话管理命令
信号机制与进程控制
信号是一种轻量级的进程间通信机制,既能由内核在异常或事件发生时产生,也能由用户通过命令或快捷键发送。
信号的概念与用例
当你按下 Ctrl+C,内核就会向前台进程发送 SIGINT,通知它“停止执行”。如果程序捕获该信号,并在处理函数里做好清理,就能优雅退场;如果未处理,进程就会被默认终止。
可以用 kill/pkill 命令给任意进程发送信号,常见用例有:
- 优雅重启:
kill -HUP PID通知进程重新加载配置 - 调试看守:
kill -USR1 PID根据约定触发进程打印状态 - 强制终止:
kill -9 PID无条件杀掉进程
常见信号列表
| 编号 | 名称 | 默认动作 | 触发方式 |
|---|---|---|---|
| 1 | SIGHUP | 终止 | 终端关闭/配置重载 |
| 2 | SIGINT | 终止 | Ctrl+C |
| 3 | SIGQUIT | 核心转储 | Ctrl+\ |
| 9 | SIGKILL | 强制终止 | kill -9 |
| 15 | SIGTERM | 终止 | kill(默认) |
| 17 | SIGCHLD | 忽略 | 子进程状态变化 |
| 18 | SIGCONT | 继续 | kill -CONT |
| 19 | SIGSTOP | 暂停 | kill -STOP(无法捕获) |
| 20 | SIGTSTP | 暂停 | Ctrl+Z |

kill、pgrep、pkill 使用方法
- kill
- 发送信号到指定 PID:
kill -SIGTERM 1234或kill 1234 - 作用于作业号:
kill -9 %1将第 1 个作业强制终止
- 发送信号到指定 PID:
- pgrep
- 查找符合条件的 PID:
pgrep sshd - 显示名称:
pgrep -l httpd - 按用户/终端/PPID 筛选:
pgrep -u laoma、pgrep -t pts/0、pgrep -P 1000
- 查找符合条件的 PID:
- pkill
- 与
pgrep类似,但直接发送 SIGTERM:pkill sleep - 可指定信号:
pkill -SIGUSR1 myapp - 按用户/终端/父进程:
pkill -u root、pkill -t pts/2、pkill -P 1350
- 与
当内置过滤无法满足需求时,经典组合为:
kill -9 $(ps axu | grep '[d]nf install' | awk '{print $2}')
登录与会话查询命令
whoami:显示当前执行用户who:列出所有登录会话及来源w:在who的基础上增加登录时间、空闲时长和当前执行命令last:读取/var/log/wtmp,显示历史登录和重启记录
特殊进程
有两类“看不见的隐患”进程需要特别关注:僵尸进程和孤儿进程
僵尸进程的形成与危害
当子进程退出后,内核并不立即销毁它的 PCB,而是将其标记为 Z(Zombie),等待父进程调用 wait() 或 waitpid() 获取退出状态若父进程迟迟不回收,这些 PCB 会一直占用内存和 PID;进程过多时,可能导致系统无法再创建新进程
预防措施
- 在父进程中捕获
SIGCHLD,在信号处理函数里调用非阻塞版waitpid(-1, …, WNOHANG)回收所有死子进程 - 对于短命任务,使用进程池或线程池替代频繁
fork()
孤儿进程的救助与注意
当父进程提前退出,子进程就会被 init(或 systemd)收养,其 PPID 自动变成 1。这样即使原父进程崩溃,子进程依然能被最终回收,不会成为僵尸
虽然孤儿进程本身不会造成死锁,但频繁生成并遗忘管理会给 init 带来额外负担。
良好实践
- 父进程对重要子进程设置合适的退出策略,避免父子脱节
- 对于短命任务,使用进程池或线程池替代频繁
fork()
孤儿进程的救助与注意
当父进程提前退出,子进程就会被 init(或 systemd)收养,其 PPID 自动变成 1。这样即使原父进程崩溃,子进程依然能被最终回收,不会成为僵尸
虽然孤儿进程本身不会造成死锁,但频繁生成并遗忘管理会给 init 带来额外负担。
良好实践
- 父进程对重要子进程设置合适的退出策略,避免父子脱节
- 必要时在代码里检测
getppid() == 1,若不希望被收养则自行退出