这个场景解决什么
跑一个可能吃资源的脚本(转码、解析超大文件、批处理)时最怕它把整机拖垮。用子 shell 加 ulimit 组成一次性的护栏,把地址空间、进程数、CPU 时间限住,再叠加 timeout 控制总时长,超限直接被杀而不是拖垮系统。长期方案应交给 systemd 单元或 cgroup 做精确计量。
基本信息
| 场景 | 给临时任务设一次性资源上限 |
|---|---|
| 组合写法 | ( ulimit 项; 命令 ) 子 shell 沙箱,再叠 timeout |
| 常用项 | -v 地址空间、-u 进程数、-t CPU 时间、-n 打开文件数 |
| 退出码 | 124 超时、137 被强杀、152 对应 CPU 时间超限 |
典型使用场景
- 解析超大日志或导数据前做兜底,避免内存被吃光
- 转码、压缩类 CPU 任务限住 CPU 时间,防止长期占用
- 第三方脚本来源不明,先隔离在资源受限的子 shell 里跑
- 批量任务并发前,先验证单个任务的资源画像
- 定时任务里加护栏,防止异常数据触发失控
- 复现线上问题时主动限资源,观察降级表现
常用护栏
常用护栏
( ulimit -v 2000000; ulimit -u 512; timeout 600 ./heavy.sh ) # 内存与进程数护栏
( ulimit -t 300; ./cpu-hog.sh ) # CPU 时间超过 300 秒被 SIGXCPU
( ulimit -n 1024; ./open-files.sh ) # 限制可打开文件数
echo "exit=$?" # 124=超时 137=被强杀 152=CPU 时间超限
ulimit -a # 先看当前 shell 的全部限制
( ulimit -v 500000; exec java --version ) # 验证限制是否会让程序起不来
systemd-run --scope -p MemoryMax=2G -p CPUQuota=50% ./heavy.sh # 长期方案常用限制项
| 选项 | 含义 | 超限表现 |
|---|---|---|
| -v | 虚拟内存地址空间 | 分配失败或直接退出 |
| -u | 用户可创建进程数 | 报资源暂时不可用 |
| -t | CPU 时间上限(秒) | 收到 SIGXCPU 结束 |
| -n | 可打开文件数 | 报打开文件过多 |
| -c | 核心转储大小 | 超限时不生成转储文件 |
ulimit -v 管的是地址空间而非实际驻留内存:Java、Go 等运行时会预留大块地址空间,限制给得太紧会直接起不来,这类应用改用 cgroup 的总内存限制更合适。
子 shell 里的限制只作用于这一条命令,父 shell 与后续命令不受影响——这正是护栏的意义。把 ulimit 写在子 shell 外面会连自己的登录会话一起限制。
长期且精确的资源限制应交给 systemd 单元(MemoryMax、CPUQuota、TasksMax)或 cgroup,它们基于 cgroup 计量,比 ulimit 更准确也更便于审计。