为什么整理这组笔记
会背 ps aux、top,不等于能解释一个程序为什么卡住。工具真正有用的地方,是把“感觉不对”转化为可以核对的证据:究竟在计算、等锁、等磁盘,还是根本没有加载到预期的动态库?
本专题由大 CC 的 Linux 工具快速教程 启发。按其工具参考篇核对,除已有 GDB 笔记外,剩余 18 个工具全部纳入。基础篇和进阶篇则与本站已有 Shell、GCC、性能分析文章连起来,不另抄一套命令手册。这里的说明、玩具程序、实验和动画是重新组织的学习材料,不是原教程的镜像或逐章翻译。
旧教程适合发现工具;具体参数和平台差异,以本机工具版本、官方手册以及本专题的实验记录为准。尤其不要把老 Linux 发行版上的截图,直接当成 Ubuntu 22.04、Docker Desktop 或现代 OpenSSH 的行为。
从哪里开始读
入口位于 知识分类 → 系统与开发环境 → Linux 与终端。本专题保留 LINUX 分类,旧文章的地址不变。
| 顺序 | 文章 | 读完要能回答的问题 |
|---|---|---|
| 01 | 进程与现场排查 | 怎么找到进程、线程、等待点、系统调用、文件描述符与 IPC? |
| 02 | 内存、I/O 与历史采样 | 哪些数字是快照,哪些是区间平均,为什么不能只看 free 或 %util? |
| 03 | ELF、符号与动态链接 | 程序、目标文件、共享库的关系是什么,库找不到与符号找不到有何区别? |
| 04 | 下载、SSH 传输与定时任务 | 怎样可靠传输文件,为什么手动运行成功的脚本在 cron 里失败? |
第一次阅读建议先看每篇的工作模型,再看 GIF,最后亲手改一次实验输入。日常查阅可以直接用侧边目录定位工具。
18 个工具的完整索引
| 工具 | 观察对象 | 典型问题 | 详细笔记 |
|---|---|---|---|
ps |
进程、线程的一次快照 | PID、父子关系、进程状态是什么? | 进程篇 |
top |
连续刷新后的任务与系统状态 | 哪个线程正在消耗 CPU? | 进程篇 |
pstack |
线程调用栈快照 | 卡住的线程位于哪条调用路径? | 进程篇 |
strace |
系统调用与信号 | 打开了哪个路径?哪个调用失败或耗时? | 进程篇 |
lsof |
进程持有的文件、socket 等 | 谁占端口?删除的日志为何仍占空间? | 进程篇 |
ipcs |
System V IPC 对象 | 共享内存、信号量、消息队列属于谁? | 进程篇 |
free |
系统内存汇总 | 空闲少,是否就意味着内存不足? | 监控篇 |
vmstat |
运行队列、内存、换页和 CPU 统计 | 多次采样后能否发现持续压力? | 监控篇 |
iostat |
CPU 与块设备统计 | 请求量、排队和等待是否同时变化? | 监控篇 |
sar |
定时采样与历史文件 | 异常发生的那个时段系统在做什么? | 监控篇 |
ldd |
动态依赖的解析结果 | 可信程序会找到哪个共享库? | ELF 篇 |
readelf |
ELF 头、节、段与动态元数据 | 架构、依赖名、搜索路径是否正确? | ELF 篇 |
objdump |
指令、重定位与对象文件信息 | 编译器实际生成了什么? | ELF 篇 |
nm |
符号定义与未解析引用 | 谁定义了函数?名称修饰是否一致? | ELF 篇 |
size |
映像的各部分大小 | .bss 增大为什么不等于文件等量增大? |
ELF 篇 |
wget |
HTTP 等协议的文件下载 | 下载是否成功,内容是否完整? | 传输篇 |
scp |
SSH 认证后的文件复制 | 怎么保留身份校验并验证传输结果? | 传输篇 |
crontab |
用户定时任务表 | 时间匹配、环境、日志、重入是否正确? | 定时篇 |
这些工具的参数层级不同:ps -p 选择 PID,top -p 也选择 PID,但不能据此推断所有工具的 -p 都一样。先认清观察对象,再查参数。
与基础篇、进阶篇怎么衔接
下面对应原教程的基础与进阶主题;不是说链接中的所有命令都在本次 18 组实验里跑过。
| 原教程主题 | 本站阅读入口 | 补强的关键点 |
|---|---|---|
| 命令帮助 | Shell 实战补充 | 内建与外部程序、man 章节、版本先行 |
| 文件和目录 | Shell 实战补充 | 含空格的文件名、NUL 分隔、先预览后操作 |
| 文本处理 | Shell 实战补充 | grep / sed / awk / sort / uniq 的分工与边界 |
| 磁盘管理 | Shell 实战补充 | df、du、inode、挂载点;不随手格式化 |
| 进程管理 | 进程篇 | 从 PID 到线程、栈、系统调用 |
| 性能监控 | 监控篇 | 连续采样、基线与资源作用域 |
| 网络工具 | Shell 实战补充 | 地址、路由、监听、HTTP 分层定位 |
| 用户管理 | Shell 实战补充 | UID/GID、目录执行权限与最小权限 |
| 系统与 IPC | 进程篇 和 Shell 实战补充 | systemd 与容器边界、IPC 命名空间 |
| 程序构建 | 原 GCC 笔记补充 | 预处理、编译、汇编、链接、自动依赖 |
| 程序调试 | 进程篇 与 ELF 篇 | 本次不重复已有 GDB 教程 |
| 性能优化 | 原性能笔记补充 | 测量口径、采样证据和修改后的复测 |
若需要交互式断点、core、观察点等内容,继续使用原 GDB 笔记。本轮没有再扩写它。
不按工具名,按症状选入口
程序卡住,但 CPU 不高
先用 ps 确认目标和状态,再取线程栈;需要时用 strace 查看等的是系统调用还是用户态同步。若看到 futex 或条件变量等待,继续追问“谁应该唤醒它”。一个空闲工作线程正常等任务,也会反复停在同一处;不能仅凭几张相同的栈就宣布死锁。
CPU 高,但业务吞吐反而下降
先区分整机和目标进程,再定位线程。top 能指出谁消耗 CPU,却不能告诉你哪一个 C++ 函数值得优化;进入函数热点分析时再接到原有 perf 笔记。还要看重试、锁竞争、自旋、日志风暴,不能只盯算法复杂度。
磁盘满了,删掉日志却没恢复
df 看文件系统统计,du 看目录树可达的文件占用,两者观察对象不同。若文件已解除目录链接,但进程仍持有打开的 FD,lsof +L1 是进一步取证的工具。后续让应用正常关闭或轮转日志,需要独立确认操作对象;不要对系统里所有打开文件批量截断。
编译成功,换机器运行失败
先记录构建与目标架构,再查 ELF 解释器、动态依赖、搜索路径和导出符号。库目录里有一个同名文件,不代表它架构相同、ABI 相容,也不代表加载器实际选中了它。先解释证据,再改 RUNPATH 或部署布局。
cron 没效果,但复制命令到终端就成功
先检查任务是否真的被调度,再检查脚本在最小环境里能否工作。工作目录、PATH、shell、时区、标准输出、权限和任务重叠是不同问题。单独通过 env -i 测试,只能证明脚本环境这一层,不能证明 cron 守护进程已按分钟运行。
GIF 怎么看,怎么复现
每个参考工具配一张操作动画和一张静态关键帧。动画使用真实命令输出重排成教学画面,不是桌面录像,也不是作者编造的一组终端结果。长命令或输出被节选时,会显示省略标记;完整输出和执行条件在下载文件中。
图片采用延迟加载,减少动态效果偏好下显示静态 PNG。动画放在各专题文章里,不把 18 张 GIF 全部塞进首页或这篇索引。
在完整仓库根目录执行:
bash docker/linux-tools-lab/run.sh build |
分别负责构建教学镜像、运行实验、渲染已通过的会话、更新公开文本快照。宿主机不需要安装 Linux 调试工具或 Pillow;Dockerfile 记录依赖与用途。该实验环境独立于 ROS、飞控与 MuJoCo,不启动那些服务。
证据与源码入口:
build/linux-tools-lab/ 保存本地实验结果。不要把 ELF、SSH 私钥、生产 core 或真实业务日志发布到文章下载目录。
三条重要的验证边界
pstack不是各发行版都一致提供的工具。若实验采用 GDB 批处理取得线程栈,会在会话和文章里说明替代实现;不能说成原生 pstack 已验证。- 容器里的
/proc、CPU 和块设备指标不一定都按容器隔离。Docker Desktop 下还有 Linux VM 这一层,单个命令截图不能证明宿主 macOS 的资源状态。 - 本机实际执行的架构与版本见验证记录。相同 Dockerfile 不代表原生 AMD64、ARM64、裸机磁盘负载和生产定时调度都已验收。
给自己留一个排查记录模板
问题:实际现象是什么,何时开始? |
不要只保存最后一条“修好了”的命令。未来换系统复现,最有价值的是操作前后的证据,以及当时为什么认为这一步能解决问题。