ulimit -m 和 limits.conf 中的 rss 项在现代内核中无效,因自 2.6.35 起 rlimit_rss 已废弃且 pam 不解析 rss;真正有效的内存限制需依赖 cgroup v2 的 memory.max,并通过 pam 在登录时将用户会话进程自动纳入指定 cgroup。

不能靠 ulimit -m 或 limits.conf 中的 rss 项真正限制用户总内存 —— 这个参数在现代内核中早已被忽略,实际无效。
为什么 ulimit -m 和 rss 在 limits.conf 里不起作用
Linux 内核自 2.6.35 起就废弃了 RLIMIT_RSS(即 ulimit -m 对应的资源限制),rss 项在 /etc/security/limits.conf 中也从未被 PAM 实际解析执行。即使你写入 * hard rss 1000000,ulimit -a 可能显示该值,但进程照样能 malloc 出几 GB 内存,OOM killer 不会因此提前介入。
-
ulimit -v(虚拟内存)仍有效,但只限制brk/mmap的地址空间总量,不防内存实际占用(如 mmap(MAP_ANONYMOUS|MAP_NORESERVE) 可绕过) -
ulimit -d(数据段)仅影响sbrk,对现代堆分配器(如 glibc malloc)基本无约束力 - 真正起效的内存隔离必须依赖 cgroup v2 的
memory.max,它由内核内存控制器强制执行
用 cgroup v2 绑定登录会话是最可靠的方式
目标不是“限制用户”,而是让该用户所有交互式登录启动的进程(包括 SSH、terminal、screen/tmux 子 shell、后台 job)自动进入同一个 memory cgroup。关键在于利用 PAM 在 login 进程启动时注入归属逻辑。
Zynq‑7000 / Zynq UltraScale+ 硬件调试技能。适用于 Xilinx Zynq(Cortex‑A9/A53 + FPGA)Linux 环境,调试 I2C、I2S、UART、GPIO 等外设。包括设备树配置、内核驱动、用户空间调试工具、交叉编译和常见问题排查,支持 PetaLinux 开发。
- 确认系统使用 cgroup v2:
mount | grep cgroup2应有输出,且cat /sys/fs/cgroup/cgroup.controllers | grep memory显示memory - 确保
/etc/pam.d/sshd和/etc/pam.d/login包含:session required pam_exec.so /usr/local/bin/assign-user-cgroup.sh -
assign-user-cgroup.sh必须用#!/bin/sh(非 bash),且第一行检查[ -z "$PAM_USER" ]防止非登录场景误触发 - 脚本中写入
$$到cgroup.procs是关键:它把 login 进程自身纳入 cgroup,其 fork 的所有子进程(包括 shell 和后续命令)自动继承 - 不要用
echo "+memory" > /sys/fs/cgroup/cgroup.subtree_control—— 这需在父 cgroup 执行,而用户级 cgroup 的 parent 通常是/sys/fs/cgroup,普通用户无权写;应直接在用户 cgroup 目录下操作
手动验证和调试时别漏掉三个文件
限制没生效?优先检查这三个路径的值是否符合预期,而不是看进程 RSS:
-
/sys/fs/cgroup/user-$USER/memory.max:必须是明确字节数(如536870912),不是max或infinity -
/sys/fs/cgroup/user-$USER/cgroup.procs:至少包含一个 PID(通常是 shell 的 PID),空文件 = 未绑定 -
/proc/$PID/cgroup(任一该用户进程):输出中必须出现user-$USER路径,且位于 memory controller 行(如0::/user-xxx) - 若看到
0::/或0::/user.slice,说明进程没进目标 cgroup —— 检查 PAM 脚本是否被跳过(比如 su 切换用户不触发 sshd/login 的 PAM session) -
memory.current值可能滞后几秒,用watch -n 0.5 cat /sys/fs/cgroup/user-$USER/memory.current观察实时变化
cgroup 的限制粒度是进程组而非用户 ID,任何绕过登录 shell 的方式(如 sudo -u user cmd、systemd --scope、cron job)都不会自动进入该 cgroup,必须单独处理 —— 这不是 bug,是设计使然。










