应直接在c++进程main()开头调用prctl(pr_set_oom_score_adj, -500)设置oom_score_adj,需cap_sys_resource权限;同时必须配合cgroup内存硬限制和合理overcommit策略,否则仅调参无效。

直接改进程的 oom_score_adj 值,不是靠配置文件或启动脚本“间接生效”
Linux 内核在 OOM 时选进程杀,核心依据是每个进程的 oom_score_adj 值(范围 -1000 到 +1000),它和实际内存占用一起参与打分。C++ 进程默认是 0,意味着“谁占得多谁先死”。你不能指望系统自动识别“这是核心服务”,必须在进程启动后、正式处理业务前,主动写入一个足够低的值。
关键点:这个操作必须由进程自己完成(或父进程代劳),且需有写 /proc/self/oom_score_adj 的权限(通常需要 CAP_SYS_RESOURCE 或 root)。
- 普通用户进程即使设置了
oom_score_adj = -500,若没权限也会被内核静默忽略,cat /proc/[pid]/oom_score_adj仍显示 0 - 建议在
main()开头就调用prctl(PR_SET_OOM_SCORE_ADJ, -500),比 fopen+write 更可靠、更原子 - 不要用 shell 重定向(如
echo -500 > /proc/$!/oom_score_adj)去设子进程的值——子进程还没 fork 出来,/proc 下对应目录都不存在
prctl(PR_SET_OOM_SCORE_ADJ, ...) 是最稳妥的 C++ 调用方式
C++ 标准库不提供封装,但 Linux 提供了 prctl() 系统调用接口,头文件是 <sys></sys>。它比手动写 /proc/self/oom_score_adj 更安全:失败会直接返回 -1 并设 errno,不会出现“以为写成功了其实被丢弃”的情况。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
示例代码片段:
int main(int argc, char* argv[]) {
// 尽早设置,避免被其他线程干扰
if (prctl(PR_SET_OOM_SCORE_ADJ, -500) != 0) {
perror("failed to set oom_score_adj");
// 可选:记录日志或降级处理,但不要退出——至少让它跑起来再观察
}
// 后续初始化、监听端口、加载配置...
}
- 值选 -500 是经验平衡点:-1000 虽然绝对安全,但可能干扰内核 OOM 判定逻辑(比如导致该进程长期卡住,拖垮整个系统)
- 如果进程以非 root 用户运行,
prctl会失败(errno == EPERM),此时应检查是否启用了CAP_SYS_RESOURCE(如 Docker 中加--cap-add=SYS_RESOURCE) - 注意:该设置只对当前进程有效,fork 出的子进程会继承该值,但 execve 后重置为 0 —— 所以子进程如需同样保护,得自己再调一次
单独设 oom_score_adj 不足以防杀,必须配合内存硬限制
很多团队踩过坑:给核心服务设了 -500,结果上线一周后还是被杀。查日志发现,OOM 发生时它的 oom_score(最终得分)依然很高,因为 process_pages(真实物理页数)太大了。公式是:points = process_pages + (oom_score_adj * totalpages / 1000)。当 process_pages 达到几 GB,-500 的抵消作用几乎可以忽略。
- 必须搭配 cgroup 内存上限(Docker 用
--memory=1g,裸机用 systemd 的MemoryLimit=1G),让process_pages有明确天花板 - 没有硬限制时,内核根本不会触发 OOM Killer 的完整评估流程;
oom_score_adj只在“已超限、要选谁杀”阶段起作用 - 验证是否生效:启动后立刻查
cat /proc/[pid]/oom_score_adj和cat /proc/[pid]/oom_score,前者应为 -500,后者应明显低于同机器上其他未设值的服务进程
别忘了 overcommit 策略的影响:malloc 成功 ≠ 内存真可用
C++ 里反复 malloc + memset 却突然被杀?大概率是 Linux 默认的 overcommit(vm.overcommit_memory=0)在作祟:它允许 malloc 返回非空指针,但实际物理页等到第一次写才分配,而那时系统可能已无页可分,直接触发 OOM Killer。
- 对核心服务,建议在启动前通过
sysctl -w vm.overcommit_memory=2关闭乐观分配(需 root),并配好vm.overcommit_ratio - 或者更务实的做法:在关键路径做主动内存预热(如启动时申请并 touch 一块预留缓冲区),把缺页异常提前暴露出来,而不是等流量进来才崩
- 这点常被忽略——你调了
prctl,也设了--memory,但没管 overcommit,OOM 依然会找上门,只是时间点更诡异
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










