Linux限制单个进程内存的推荐方式是cgroup v2(最精准)、systemd-run(最便捷)、ulimit(轻量但局限大);cgroup v2需启用memory控制器并设memory.max与memory.swap.max=0;systemd-run适合临时任务;ulimit仅限shell场景且不可靠。

Linux 中限制单个进程的最大内存使用,不能靠“给一个 PID 加锁”这种直觉方式——因为内存是按进程组(cgroup)管理的,且限制需在进程启动时或早期介入才可靠。实际可用、推荐的方式有三种:cgroup v2(最精准)、systemd-run(最便捷)、ulimit(轻量但局限大)。下面分场景说明。
cgroup v2:精确控制物理+虚拟内存上限
这是现代 Linux(Ubuntu 22.04+/Fedora 31+/RHEL 9+)首选方案,能真正约束进程及其所有子进程的总内存占用(含 page cache、anon memory),并支持 OOM 控制策略。
- 确认启用:
mount | grep cgroup2应看到挂载点;cat /sys/fs/cgroup/cgroup.controllers | grep memory应含 memory - 若未启用 memory 控制器,执行:
echo "+memory" | sudo tee /sys/fs/cgroup/cgroup.subtree_control - 创建并设限(例如 800MB):
sudo mkdir /sys/fs/cgroup/myappecho 838860800 | sudo tee /sys/fs/cgroup/myapp/memory.maxecho 0 | sudo tee /sys/fs/cgroup/myapp/memory.swap.max(禁用 swap,确保只限物理内存) - 将新进程加入该组:
systemd-run --scope -p MemoryMax=800M -- bash -c "your_command"(推荐)
或对已运行进程(仅限其自身,不继承子进程):echo $PID | sudo tee /sys/fs/cgroup/myapp/cgroup.procs
systemd-run:一键启动带内存限制的临时进程
无需手动建目录、写配置,适合脚本调用或运维临时任务,底层仍走 cgroup v2,安全可靠。
- 限制 1GB 内存 + 50% CPU:
systemd-run --scope -p MemoryMax=1G -p CPUQuota=50% python3 app.py - 限制生效后,进程超出会分配失败(malloc 返回 NULL)或触发 OOM killer 杀掉该 cgroup 内最重的进程
- 注意:
--scope表示临时单元,退出即销毁;如需长期服务,请写 .service 文件并设置MemoryMax=
ulimit:仅限 shell 启动的简单场景,慎用于生产
ulimit 是 shell 级限制,只影响当前会话及 fork 出的子进程,且只管虚拟地址空间(-v)或 RSS(-m,已部分失效),无法防止 mmap、page cache 等绕过行为,也不约束子进程继承外的派生行为。
- 限制虚拟内存为 2GB:
ulimit -v 2097152(单位 KB) - 限制常驻内存(RSS)为 1GB:
ulimit -m 1048576(注意:-m 在多数内核中已被忽略,不可靠) - 永久生效需写入
/etc/security/limits.conf,例如:username soft as 2097152username hard as 2097152 - ⚠️ 关键限制:Java、Python 等运行时默认不遵守 -m;-v 对 mmap(MAP_ANONYMOUS) 分配可能无效;无法限制已运行进程
别踩这些坑
memory.max 不是“超了就立刻杀”,而是内核在每次内存分配时检查——所以进程可能已占 950MB,你设 1G,它还能 malloc 成功几次;真超了才会失败或触发 OOM。
- 不要用 cgroup v1(
cgcreate/cgset),已弃用,行为不一致 - 不要依赖
ulimit -l(锁定内存限制),它只管 mlock(),和普通内存占用无关 - 想真正“物理内存 ≤ X”,必须同时设
memory.max和memory.swap.max=0 - 已有进程无法被完整纳入限制——fork 出的子进程不会自动进入父进程所在的 cgroup,除非用 systemd-run 启动整个树


















