Linux中OOM是系统内存压力下OOM Killer主动终止进程自救,非真正耗尽内存;可通过cgroups设硬限、ulimit -v控虚拟内存、应用层监控RSS并处理分配失败来主动限制单进程内存。

Linux 系统中出现“内存溢出”(OOM)并非内核真的耗尽所有内存,而是当系统无法为新内存申请分配足够页帧、且无法通过回收缓存或交换空间缓解时,OOM Killer 被触发,强制终止一个或多个进程以自救。此时进程被杀通常不是因为自身设置了硬性限制,而是系统全局内存压力下的被动选择。但你确实可以通过多种机制对单个进程的内存使用施加主动限制,从而避免它成为 OOM Killer 的目标,或提前阻止其无节制增长。
1. 使用 cgroups v1 或 v2 限制进程内存上限
cgroups 是 Linux 控制资源使用的标准机制,v2 更简洁统一,推荐优先使用:
-
v2 示例(推荐):创建 memory controller 子树,写入最大允许内存(如 512MB):
mkdir /sys/fs/cgroup/myapp<br>echo 536870912 > /sys/fs/cgroup/myapp/memory.max<br>echo $$ > /sys/fs/cgroup/myapp/cgroup.procs # 将当前 shell 加入
后续在此 cgroup 中启动的进程(如./myserver)将被严格限制在 512MB 内,超限时会被 kernel OOM killer 杀掉(注意:是该 cgroup 内部的 OOM,非全局)。 -
v1 兼容方式:使用
memory.limit_in_bytes和memory.soft_limit_in_bytes,但需确保memory子系统已挂载,且配置更分散。
2. 启动时用 ulimit 限制虚拟地址空间(适用于 shell 启动的进程)
ulimit -v 可设进程最大虚拟内存(单位 KB),对 malloc/new 分配生效,但不控制 mmap、共享内存或 page cache:
ulimit -v 524288 # 限制为 512MB 虚拟内存- 随后运行
./myprogram,若尝试分配超过该值的虚拟地址空间,系统调用(如brk或mmap)会直接返回ENOMEM,程序可捕获错误处理,而非等到 OOM Killer 干预。 - 注意:
ulimit -m(物理内存)在多数现代内核中已被忽略,不可依赖。
3. 应用层配合:启用内存分配失败检查 + 设置 RSS 上限告警
内核不主动通知进程“快超限了”,但你可以主动监控:
- 定期读取
/proc/[pid]/statm或/proc/[pid]/status中的VmRSS字段,判断实际物理内存占用。 - 在关键路径中检查 malloc 返回值是否为 NULL(尤其在嵌入式或严控环境);C++ 中可设置
new_handler捕获分配失败。 - 结合 cgroups 的
memory.high(v2)实现软限:当 RSS 接近该值时,内核会开始积极回收该 cgroup 的 page cache,避免直接触发 OOM —— 这比硬限更友好。
4. 避免误判:区分“OOM Killer 日志”与“应用主动退出”
确认是否真由 OOM 导致进程消失:
- 查
dmesg -T | grep -i "killed process",若看到类似Killed process 1234 (java) total-vm:2048000kB, anon-rss:819200kB, file-rss:0kB,即为 OOM Killer 所为。 - 若进程日志显示
std::bad_alloc、Cannot allocate memory或崩溃在 malloc,大概率是 ulimit -v 触发或应用未处理分配失败,而非系统级 OOM。 - 注意 swap 启用状态:有 swap 时 OOM 更晚发生,但延迟高;禁用 swap(
swapoff -a)可让内存压力更早暴露,利于测试限制策略有效性。










