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
,若不希望被收养则自行退出