Skip to content

strace / ltrace:看进程在等什么 ​

进程"卡住"但日志没输出、CPU 不高、连接也没断——这时要知道它卡在哪个系统调用上。strace 是唯一能直接给出答案的工具。

场景 ​

  • 应用启动卡住,没有任何日志。
  • 请求超时,但不知道卡在 DNS、连接、还是读数据。
  • 文件"打不开",但权限看着没问题。

一、attach 到运行中的进程 ​

bash
strace -p 28441
text
strace: Process 28441 attached
futex(0x7f2c1e9a2b40, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 0, NULL, FUTEX_BITSET_MATCH_ANY) = 0
epoll_wait(42, [{EPOLLIN, {u32=183, u64=183}}], 1024, 1000) = 1
read(45, "\x16\x03\x03\x01\x2b", 16384) = 5
write(46, "HTTP/1.1 200 OK\r\n", 17) = 17

读法:进程阻塞在某个调用上不动(比如一直 futex、read 没返回),那就是卡点。

按 Ctrl+C 脱离,进程不受影响(Ctrl+Z 才会让它停)。

attach 需要权限

普通用户只能 attach 自己的进程。attach 别人的进程要 root,或者满足 ptrace_scope 的规则:

bash
cat /proc/sys/kernel/yama/ptrace_scope

值为 1 时只能 attach 子进程。临时放开(重启失效):

bash
echo 0 > /proc/sys/kernel/yama/ptrace_scope

二、按类别过滤 ​

strace 默认输出所有调用,量非常大。用 -e trace= 过滤:

bash
# 文件相关(启动卡住最常用)
strace -p 28441 -e trace=file

# 网络相关
strace -p 28441 -e trace=network

# 指定具体调用
strace -p 28441 -e trace=openat,read,write,close

# 排除某些
strace -p 28441 -e trace=!futex,epoll_wait

file 等价于 openat,stat,access,readlink,... 一整组。查"到底在找哪个配置文件"特别有效:

bash
strace -f -e trace=openat ./app 2>&1 | grep -v ENOENT | head -20
text
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/opt/app/config/application.yml", O_RDONLY) = 4

= -1 ENOENT 表示文件不存在。Java 启动时会有大量 ENOENT(类路径扫描),属正常,别被吓到。

三、看耗时 ​

bash
strace -p 28441 -T -e trace=network
text
connect(7, {sa_family=AF_INET, sin_port=htons(3306), sin_addr=inet_addr("10.0.0.32")}, 16) = 0 <0.000214>
sendto(7, "\x2f\x00\x00\x00\x03SELECT 1", 15, 0, NULL, 0) = 15 <0.000018>
recvfrom(7, "\x07\x00\x00\x01", 16384, 0, NULL, NULL) = 7 <2.014211>

<2.014211> 是这次调用花了 2.01 秒。recvfrom 花了 2 秒,说明在等数据库响应。

-T 是单次调用耗时,-tt 是绝对时间戳,两个常一起用:

bash
strace -tt -T -p 28441 -e trace=network
text
22:20:11.114221 connect(7, {...}, 16) = 0 <0.000214>
22:20:11.114402 sendto(7, "...", 15, 0) = 15 <0.000018>
22:20:13.128613 recvfrom(7, "...", 16384, 0) = 7 <2.014211>

四、-y:显示文件描述符对应的路径 ​

bash
strace -y -p 28441 -e trace=read,write
text
read(45</etc/nginx/nginx.conf>, "user nginx;\n", 4096) = 13
write(46</var/log/app/app.log>, "started\n", 8) = 8

不加 -y 只会显示 read(45, ...),你还得去 /proc/28441/fd/45 查它是什么。-y 能省大量时间。

五、-c:统计各调用 ​

bash
strace -c -f -p 28441
text
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 78.42    4.213004      421300        10           epoll_wait
 12.11    0.650881          81       8021           read
  5.02    0.269441          33       8102           write
  2.34    0.125772          15       8401           futex
------ ----------- ----------- --------- --------- ----------------
100.00    5.372210                 24612           total

看两列:% time 和 errors。

  • 某个调用占比特别高 → 瓶颈在这里。
  • errors 特别多 → 在反复重试(比如 connect 大量 ECONNREFUSED)。

六、常用排查模板 ​

启动卡住 ​

bash
strace -f -tt -T -o /tmp/start.trace /opt/app/bin/start.sh
tail -50 /tmp/start.trace

看最后几行卡在哪个调用。常见:

卡在原因
connect 无返回网络不通(防火墙 DROP,不是 REJECT)
read 无返回对端没发数据
openat 大量 ENOENT 后极慢在遍历不存在的路径(配置错)
futex 长时间等锁(死锁或线程池耗尽)
poll/epoll_wait正常空闲,不是卡住

请求超时 ​

bash
# 先确认是不是在等网络
strace -f -p $(pgrep -f app.jar | head -1) -e trace=network -T -tt

如果看到 connect 直接 EINPROGRESS 然后超时,是 TCP 层不通;如果 sendto 成功但 recvfrom 超时,是下游处理慢。

文件打不开 ​

bash
strace -e trace=openat,access -y ./app 2>&1 | grep -E 'ENOENT|EACCES'
text
openat(AT_FDCWD, "/opt/app/conf/app.yml", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/data/app/logs", O_WRONLY|O_CREAT, 0644) = -1 EACCES (Permission denied)

ENOENT 是路径错,EACCES 是权限问题——比应用日志里的"配置文件加载失败"精确得多。

七、ltrace:看库函数调用 ​

bash
ltrace -p 28441
ltrace -c -p 28441
text
malloc(4096) = 0x55d3c1e2a010
strcmp("prod", "prod") = 0
snprintf("/data/app/logs/app.log", 256, "%s/%s.log", "/data/app/logs", "app") = 24

ltrace 拦的是动态库函数(libc 的 malloc、strcmp、snprintf)。用途比 strace 窄,主要是:

  • 确认某个库函数被调用了。
  • 看参数(比如 snprintf 拼出来的路径对不对)。

对 Java 这类自己管理内存的程序,ltrace 帮助不大。

八、性能影响 ​

strace 会让被跟踪进程慢几十倍,因为每次系统调用都要陷入内核两次。

text
正常 QPS 5000 → strace 后 80

不要长时间在生产上 strace 高流量进程

两个后果:

  1. 应用直接超时。
  2. strace 输出文件能几分钟写满磁盘。

正确做法:

bash
# 限定时间
timeout 10 strace -f -p 28441 -e trace=network -T -o /tmp/t.trace

# 限定类别
strace -e trace=connect -p 28441

# 写到 tmpfs
strace -o /dev/shm/t.trace ...

九、和 perf / bpftrace 的分工 ​

工具看什么开销
strace具体某次系统调用的参数和耗时高
perf top/trace函数级 CPU 分布中
bpftrace自定义探针,聚合统计低

strace 适合"单个进程卡住"的定性排查;要看"整体哪个函数最热"用 perf;要长期低开销观测用 bpftrace。

十、踩过的坑 ​

现象根因处置
strace: attach: ptrace(PTRACE_ATTACH...): Operation not permitted权限/ptrace_scope用 root,或调 ptrace_scope
输出刷屏,找不到重点没加 -e trace=按类别过滤
找不到 fd 对应文件没加 -y加 -y
进程被 strace 拖死系统调用太频繁timeout 5 限时
-c 统计里 futex 占比高等锁结合 jstack/perf 看锁竞争
Java 进程没有有用的库调用JIT 后不经过 libc 调用点用 perf/async-profiler
输出的字符串被截断默认 -s 32-s 200