进程被内核挂起时ps显示T/t状态,wchan为freezer_do_wait可确认cgroup freezer冻结;若为do_wait或ep_poll则属用户态阻塞;dmesg和cgroup状态是关键线索。

线程被挂起通常不是应用层问题,而是内核资源管控触发的冻结(freeze)或调度拒绝,ps 显示 T 状态时,dmesg 和 cgroup 状态才是关键线索。
怎么看进程是不是真被内核挂起了
运行 ps -o pid,comm,state,tid,wchan -T -p $PID,重点看 state 列是否为 T(stopped)或 t(traced),同时观察 wchan 是否为空或显示 freezer_do_wait。若出现后者,基本可断定是 cgroup freezer 主动冻结所致;若为 do_wait 或 ep_poll,则更可能是用户态阻塞(如锁、IO),而非内核强制挂起。
注意:kill -STOP、gdb attach、ptrace 也会让 state 变成 T,但这类挂起不会触发内核日志,也不会影响其他同 cgroup 进程。
查 Freezer cgroup 冻结状态(旧内核)
在内核
立即学习“C++免费学习笔记(深入)”;
- 先确认进程所属 cgroup:运行
cat /proc/$PID/cgroup | grep freezer,提取出类似freezer:/system.slice/myapp.service的路径 - 然后执行
cat /sys/fs/cgroup/freezer/system.slice/myapp.service/freezer.state - 若输出为
FROZEN,说明该 cgroup 下所有线程已被内核冻结;若为THAWED,则排除 freezer 干预
此时 dmesg -T 中大概率会出现 freezer: Freezing cgroup ... failed: -EBUSY 或 Freezing of cgroup ... aborted —— 这类日志表明冻结尝试失败,但已部分生效,线程可能卡在中间状态。
Linux系统管理专家,覆盖12大模块:用户权限、SSH、存储、网络、systemd、防火墙、日志监控、备份恢复、TLS证书、Ansible、容器、IaC。提供配置、验证、加固、监控、备份、自动化、故障排查、回滚闭环。关键词:useradd、sudo、sshd_config、chmod、SEL...
查 systemd 冻结状态(新内核 ≥5.11)
新版内核移除了 /sys/fs/cgroup/freezer/,改由 systemd 统一管理。直接查服务状态即可:
- 运行
systemctl show myapp.service | grep FreezerState,若输出FreezerState=FROZEN,即确认被冻结 - 也可用
systemctl status myapp.service,观察是否有 “FreezerState: frozen” 字样出现在详细信息中 - 配套检查内存限额是否触顶:
systemctl show myapp.service | grep MemoryCurrent与MemoryMax对比,若接近或等于,可能触发了 memory.low 或 oom_kill
注意:TasksMax= 被超限时,systemd 会静默拒绝新线程创建(pthread_create 返回 EAGAIN),但已有线程不会被挂起——这点常被误判为“线程卡死”。
从 dmesg 挖资源拒绝的原始痕迹
内核对资源分配失败(非 OOM killer 主动杀进程)的记录非常克制,但以下命令能挖出关键线索:
-
dmesg -T | grep -i "cgroup.*memory\|oom\|freezer"—— 容器或 systemd 场景下最相关 -
dmesg -T | grep -A1 -B1 "Out of memory"—— 注意它不一定伴随 kill 记录,有时仅冻结 -
dmesg -T | grep -i "pid.*comm.*blocked"—— 少数内核配置下会记录因 cgroup 配额阻塞的线程
如果 dmesg 完全安静,而 ps 又持续显示 T,大概率是用户态行为(如调试器暂停、ptrace、手动 kill -STOP),此时应检查 /proc/$PID/status 中的 TracerPid 是否非零,以及 State 行是否含 (traced)。
真正容易被忽略的是:cgroup 冻结不保证原子性,freezer.state 切换过程中,部分线程可能已进入 T 状态但未完全同步,导致 ps 看似卡住,实则正处在内核冻结路径的临界区——这种状态不会报错,也几乎不留日志,只能靠反复 cat /proc/$PID/status 观察 State 和 voluntary_ctxt_switches 是否停滞来交叉验证。

















