最准方法是用 ps -o pid,ppid -e | awk '$2 == pid' | wc -l 统计直接子进程数,pgrep -p pid 更适合脚本自动化;pstree 因混入线程、忽略僵尸进程等易误判。

ps -o pid,ppid 查子进程数最准,别信 pstree 的缩进
直接统计子进程数量,ps 比树状图工具更可靠。因为 pstree 会把线程也当子节点、忽略僵尸进程、默认不显示跨用户进程,导致计数虚高或漏掉。
正确做法是用 ps -o pid,ppid -e 抓出所有进程的 PID 和父 PID,再按目标 PID 统计匹配的 ppid 行数:
-
ps -o pid,ppid -e | awk '$2 == 1234' | wc -l—— 得到 PID 为 1234 的**直接子进程数** - 注意:结果不含已僵死(Z 状态)但未被回收的子进程,它们的
ppid仍有效,所以这条命令能捕获到 - 若目标进程刚 fork 完还没 exec,子进程可能短暂处于
R或S状态,ps能立刻看到,pstree有时刷新滞后
pgrep -P 是脚本里数子进程的首选
需要在自动化任务中判断服务是否派生出 worker 进程,pgrep -P 是唯一干净的选择:它只输出 PID 列表,无标题、无空格、无额外字段。
-
pgrep -P 5678 | wc -l—— 快速返回子进程数量,适合 if 判断或循环条件 - 它只查**直接子进程**,不递归;如果要统计整个子树(含孙子),得配合
pstree -p 5678 | grep -oE '\([0-9]+\)' | grep -oE '[0-9]+' | wc -l - 容器环境里,宿主机上运行
pgrep -P可能查不到容器内进程——因为 PID namespace 隔离,此时必须nsenter -t $CONTAINER_PID -p -- pgrep -P $PID
forkstat 实时监控 fork/exec/exit 行为,但需 root 权限
想确认某个程序是否频繁 fork(比如内存泄漏或恶意行为),forkstat 是唯一能实时抓系统调用级事件的工具,不是查快照,而是监听内核 netlink connector。
-
sudo forkstat -e fork,exec—— 显示每次 fork 和 exec 的时间、父子 PID、进程名 - 输出中
Info列标parent或child,可清晰追溯派生链 - 它依赖
netlink connector,高负载下可能丢事件;且无法看到已退出但未 wait 的子进程(即僵尸进程的残留) - 普通用户不能用,必须
sudo;某些最小化系统(如 Alpine)默认不带,需apk add procps-ng或等价安装
procfs /proc/[pid]/status 里的 Threads 和 Children 字段有误导性
/proc/[pid]/status 文件里确实有 Threads: 和 Children: 行,但它们不是你想要的“子进程数”。
-
Threads:是该进程自身线程数(即gettid()数量),和 fork 出的子进程无关 -
Children:字段**实际不存在**——这是常见误解;Linux 内核从没在 status 中暴露子进程列表,很多文章写的 “Children: 3” 是伪造或混淆了 cgroup 的统计 - 真要靠 procfs,只能遍历
/proc/[pid]/task/[tid]/status看线程,或扫描整个/proc目录找PPid:匹配值,效率极低,不推荐
实际用的时候,多数场景只需要知道“有没有子进程”和“有几个”,pgrep -P 加 wc -l 就够用;只有当你怀疑 fork 频率异常、或者要审计启动链路时,才值得开 forkstat 并守着终端看输出。











