答案是:需执行dmesg -T | grep -i "page allocation failure|low memory|watermark"查找关键信号,再结合/proc/pid/stack确认进程是否卡在__alloc_pages_slowpath等内核分配路径。

查 dmesg 里有没有 “page allocation failure”
进程没被杀、也没报错,但卡住不动——这种“挂起”往往不是进程自己停的,而是内核在分配内存时失败后陷入等待或重试,最终表现为进程僵死。最直接证据就在内核环缓冲区里。page allocation failure 是关键信号,比 Out of memory 更早出现,也更贴近“分配失败导致挂起”的本质。
执行:dmesg -T | grep -i "page allocation failure\|low memory\|watermark"
如果看到类似:
[Tue Jul 7 23:41:02 2026] lowmemorykiller: Killing 'java' (12345), adj 0, to free 12345kB on node 0 [Tue Jul 7 23:41:02 2026] page allocation failure: order:4, mode:0x140cca
说明内核已无法满足连续 2^4=16 页(默认页大小 4KB,即 64KB)的分配请求,触发了内存回收甚至直接 kill,但某些路径下(比如 GFP_ATOMIC 上下文)连 kill 都来不及,进程就卡在 __alloc_pages_slowpath 里了。
- order 值越大,说明需要的连续物理页越长,越容易失败(尤其在内存碎片严重时)
- mode 字段里的
GFP_ATOMIC或GFP_NOWAIT表示该分配不能睡眠,失败即阻塞,不抛异常也不返回 - 没有
Killed process不代表安全,可能只是还没轮到 kill,或者进程卡在分配路径上没机会被选中
看 /proc/[pid]/stack 确认进程是否卡在内存分配栈
找到疑似挂起的进程 PID 后,直接读它的内核调用栈:cat /proc/12345/stack
如果输出里反复出现 __alloc_pages_slowpath、wait_event_killable、try_to_free_pages,基本可以断定它正卡在内存分配或回收路径上。
常见卡点:
Linux系统管理专家,覆盖12大模块:用户权限、SSH、存储、网络、systemd、防火墙、日志监控、备份恢复、TLS证书、Ansible、容器、IaC。提供配置、验证、加固、监控、备份、自动化、故障排查、回滚闭环。关键词:useradd、sudo、sshd_config、chmod、SEL...
-
__alloc_pages_nodemask → __alloc_pages_slowpath → wait_event_killable:等待内存回收完成,但回收迟迟无法释放足够页 -
shrink_slab → shrink_node → shrink_page_list:正在尝试回收 slab 或页面,但压力太大收不回来 - 空栈或只有一行
[<0000000000000000>] 0x0:进程处于不可中断状态(D 状态),通常就是卡在上述内核路径里
用 vmstat 和 pidstat 捕捉分配失败前的内存压力信号
单纯查日志是回溯,要提前预警得靠实时指标。重点盯三个信号:
-
vmstat 1中的pgpgin/pgpgout持续飙升,且pgmajfault> 100/s:说明频繁缺页,已在透支 page cache -
pidstat -r 1显示某进程%mem稳定但VSZ暴涨、RSS不涨:可能是 mmap 大块地址空间但未实际分配物理页,一旦 touch 就卡住 -
cat /proc/zoneinfo | grep -A5 "Node [0-9] DMA\|Normal\|HighMem"中的pagesets下free接近 0,且lowwatermark 被持续击穿:内核已进入紧急回收模式
这些不是“失败记录”,而是失败前几秒的确定性征兆。真等到 page allocation failure 出现,往往已经晚了。
注意 /var/log/messages 里没有对应记录是正常的
dmesg 是唯一可靠来源,/var/log/messages 或 journalctl 很可能压根不收录 page allocation failure 这类底层警告——它们默认过滤掉 kernel log level KERN_ERR 以下)的消息。而 page allocation failure 通常是 KERN_WARNING(level 4),dmesg 默认全量抓取,rsyslog 却可能丢弃。
验证方式:dmesg | head -n 20 | grep -o "level=[0-9]" 查看实际日志等级grep -r "level.*4" /etc/rsyslog.conf /etc/rsyslog.d/ 看是否配置了接收 WARNING 级别
所以别在 journalctl 里白费时间搜这个关键词,dmesg -T 才是第一现场。

















