14 10 月 2026

进程行为异常时,光看日志不够:程序卡住不知道在等什么、文件句柄泄露不知道为什么、CPU 飙高不知道耗在哪。

这篇讲三个底层调试工具:strace(看系统调用)、lsof(看文件句柄)、perf(看 CPU 热点)。不需要改代码,就能把黑盒程序看穿。

需要云服务器可以看看财富云计算:一键开服面板,NAT 型无独立公网 IP,价格比独立 IP 机型省一半以上,主流游戏快速部署。

一、什么时候用哪个

症状工具看什么
程序卡住不动strace -p PID卡在哪个系统调用
句柄数暴涨、报 too many open fileslsof -p PID开着哪些文件/连接
CPU 100% 但不知道哪段代码perf top热点函数
程序启动就退出,不知道原因strace 程序名退出前最后一个调用
端口被占用找不到进程lsof -i :端口谁占的
内存只涨不降pmap + lsof内存映射和泄漏的 fd

二、strace:跟踪系统调用

strace 记录程序和内核之间的每一次交互:打开什么文件、连什么网络、读什么、卡在哪。

1. 程序卡住了:看它在等什么

# 找到进程 PID
pgrep -f PalServer

# attach 上去看实时系统调用
strace -p PID

# 输出示例:
# futex(0x7f..., FUTEX_WAIT, ...) = -1 EAGAIN     ← 在等锁
# read(5,                                  ← 卡在读文件/网络,等数据
# nanosleep({tv_sec=1}, {tv_sec=0}) = 0     ← 在睡觉,正常空闲

判读:

卡住的调用含义
futex等锁(线程死锁/锁竞争)
read/recvfrom 无返回等数据(网络慢/对端不回)
nanosleep正常休眠
wait4等子进程
flock/fcntl等文件锁

2. 程序启动失败:看它读了什么

strace -f -e trace=file ./program 2>&1 | tail -30
# 能看到它尝试打开哪些配置文件,哪个不存在(ENOENT)导致失败

游戏服启动失败的经典场景:缺 32 位库、找不到配置文件、权限不足(EACCES),strace 一眼定位。

3. 网络连接问题

# 只看网络相关调用
strace -p PID -e trace=network

# 看 DNS 解析
strace -e trace=connect,sendto,recvfrom ./program | head

4. 统计模式(开销小)

# 不跟每条调用,只统计
strace -c -p PID
# 跑 10 秒 Ctrl+C,看哪类调用最多、哪类最慢

常用参数

参数作用
-p PIDattach 到运行中的进程
-f跟踪子进程/线程
-e trace=file只看文件相关调用
-e trace=network只看网络相关
-c统计摘要
-s 200字符串显示长度(默认 32 太短)
-t/-tt加时间戳
-o file输出到文件

注意:strace 用 ptrace,会拖慢目标进程(2–20 倍)。生产环境短时间用,别长期挂着。

三、lsof:文件句柄侦探

Linux 一切皆文件——打开的文件、网络连接、管道,都是 fd(文件描述符)。

1. 句柄泄漏排查

# 进程开了多少 fd
ls /proc/PID/fd | wc -l

# 系统上限
cat /proc/sys/fs/file-max
ulimit -n

# 具体开了什么(按类型归类)
lsof -p PID | awk '{print $5}' | sort | uniq -c | sort -rn

# 看具体的连接(找泄漏的连接)
lsof -p PID -i -a -P -n | head -30

报 too many open files 时:要么调大 ulimit -n,要么程序在泄漏 fd——lsof 看增长的是哪类(通常是 socket),找程序 bug。

2. 端口占用

# 谁占了 8080
lsof -i :8080

# 所有监听端口和进程
lsof -i -P -n | grep LISTEN

# 比 ss 好在能直接看到进程名和用户

3. 谁在动我的文件

# 谁打开了 /var/log/syslog
lsof /var/log/syslog

# 谁打开了删除但空间没释放的文件(经典坑!)
lsof +L1
# 输出里 SIZE/OFF 大 + NLINK 0 的,就是删了还被占着的

4. 卸载磁盘报 busy

# 谁在用 /data
lsof /data
# 杀进程或 fuser -k /data

5. 看进程的工作目录和加载的库

lsof -p PID | grep -E "cwd|txt|mem"
# cwd = 当前目录(找程序在哪运行)
# txt = 可执行文件(确认是不是被替换过的)

四、perf:CPU 热点分析

perf 是 Linux 的性能剖析神器,直接看 CPU 周期花在哪些函数上。

1. 实时热点

# 安装
apt install -y linux-tools-common linux-tools-$(uname -r)

# 实时看(类似 top,但按函数排)
perf top

# 只看某个进程
perf top -p PID

# 看内核热点
perf top -k

2. 记录并分析

# 记录 30 秒
perf record -F 99 -p PID -g -- sleep 30

# 生成报告
perf report

报告里看:

  • Overhead 列:该函数占的 CPU 比例
  • 调用链(-g):谁调用了它
  • 自己的代码 vs 库函数 vs 内核

3. 常见场景

perf top 看到结论
libc 内存函数(malloc/memcpy)内存操作密集
内核 copy_user频繁用户态/内核态拷贝(大量 IO)
spin_lock/mutex锁竞争严重
自己的业务函数算法问题,优化代码
sys_ioctl 高频繁系统调用,批处理能优化

4. 容器里的 perf

容器内 perf 权限受限。两种方案:

# 1. 容器加权限
docker run --cap-add SYS_ADMIN --security-opt seccomp=unconfined ...

# 2. 在宿主机跑 perf -p 容器内进程的宿主机 PID
# (docker top 或 ps 看到宿主 PID)

五、实战案例

案例 1:游戏服半夜卡死

# 1. 进程还在但没响应
pgrep -f PalServer    # PID 12345

# 2. strace 看卡在哪
strace -p 12345
# futex(0x7f8a... FUTEX_WAIT ...   ← 等锁

# 3. 看线程在干什么
ls /proc/12345/task/ | wc -l       # 32 个线程
for t in /proc/12345/task/*; do cat $t/stack 2>/dev/null; done | sort | uniq -c
# 多个线程卡在同一个 futex = 锁竞争/死锁

# 4. perf 看是谁持有锁
perf record -p 12345 -g -- sleep 10
perf report
# 发现某个线程 spin_lock 占了 40% CPU = 死循环抢锁

# 结论: 游戏服 bug,重启临时恢复,反馈官方或换版本

案例 2:句柄耗尽

# 1. 报错
tail /var/log/myapp.log
# java.net.SocketException: Too many open files

# 2. 看 fd 数在涨
watch -n 2 'ls /proc/PID/fd | wc -l'
# 从 2000 涨到 65000(ulimit 上限)

# 3. 看是什么 fd
lsof -p PID -i -a -P -n | awk '{print $8, $9}' | sort | uniq -c | sort -rn | head
# ESTABLISHED 的连接几千个不释放 = 连接泄漏

# 4. 处置
# 短期: ulimit -n 65535 + 重启
# 长期: 修程序的连接池(关闭响应不读 body 之类)

案例 3:端口莫名被占

lsof -i :8211
# COMMAND   PID   USER   FD   TYPE  NODE NAME
# PalServe 12345 steam  10u  IPv4  12345 UDP *:8211
# 原来是上一个没杀干净的实例,重启即可

六、工具组合拳速查

# 「程序卡了」排查链
pgrep -f 进程名                    # 1. 找 PID
strace -p PID                      # 2. 看卡在哪个调用
cat /proc/PID/status | grep Thread # 3. 线程数
perf top -p PID                    # 4. 看 CPU 花在哪

# 「资源异常」排查链
lsof -p PID | wc -l                # fd 数
ls /proc/PID/fd | wc -l            # fd 数(另一种)
cat /proc/PID/limits               # 该进程的资源上限
pmap -x PID | tail -1              # 内存映射总量

七、常见问题

Q:strace 一 attach 进程就挂了?
ptrace 被禁(容器默认 seccomp 拦 ptrace)或 SELinux/AppArmor 限制。容器加 --cap-add SYS_PTRACE。

Q:perf 报 perf_event_paranoid?

# 降低限制(宿主机)
echo 1 > /proc/sys/kernel/perf_event_paranoid
# 或永久: echo 'kernel.perf_event_paranoid=1' >> /etc/sysctl.d/99-perf.conf

Q:lsof 输出太多看不到重点?
加过滤:lsof -p PID -i(只看网络)、lsof -p PID | grep REG(只看普通文件)、lsof -p PID | grep -c REG(数普通文件)。

Q:strace/perf 开销大吗?
strace 大(每条调用都拦截,2–20 倍减速),perf 小(硬件计数器采样,< 5%)。生产环境 perf 可以常开采样,strace 只短时间用。

Q:这些工具在 Windows 上有对应吗?
strace ≈ Process Monitor,lsof ≈ handle.exe/Resource Monitor,perf ≈ WPA。Linux 上这三个是标配,建议 SSH 上去看。

小结

进程调试的核心思路:卡住看 strace(等什么)、句柄异常看 lsof(占什么)、CPU 异常看 perf(耗在哪)。三个工具都不需要改代码,attach 上去就能看到进程的内幕。配合 /proc/PID/ 下的信息,90% 的疑难杂症能定位到根因。

更多运维内容见财富云计算知识库:性能分析三板斧、日志管理、进程管理、监控体系全系列。需要云服务器可以看看财富云计算:一键开服面板,NAT 型无独立公网 IP,价格比独立 IP 机型省一半以上。

延伸阅读
  1. 网站环境怎么选:LNMP 手动 / 宝塔面板 / Docker / 云开发
  2. 问卷表单系统搭建:SurveyKing / Formbricks,数据自己收
  3. 图床搭建:Lsky Pro / Lychee,自托管图片托管方案
  4. 邮件列表搭建:listmonk 自托管 Newsletter,把读者握在自己手里
  5. 文档站点搭建:MkDocs / VuePress / Docsify,产品文档与技术手册方案
  6. RSS 阅读器搭建:FreshRSS 自托管,把信息流拿回自己手里
  7. 短链接服务搭建:Shlink 自托管,链接数据自己掌握
  8. 网站状态监控页搭建:Uptime Kuma,服务器挂了第一时间知道
更多阅读
  1. 上一篇:数据泄露应急响应与合规要点:出了事怎么按步走
  2. 下一篇:tcpdump 抓包实战:从入门到定位网络问题
发表评论 3