AI / 自动化 2026年4月22日

2026:在 launchd 管理的租用 Mac mini 上,为 OpenClaw 设置 ulimit、内存与 CPU 护栏

ProxyMac 工程团队 2026年4月22日 约 12 分钟阅读

位于香港、日本、韩国、新加坡或美国ProxyMac Mac mini M4 上,OpenClaw 常在常驻内存(RSS)越过 launchd 隐式边界时“悄悄死掉”:进程状态仍显示运行,但频道适配器不再接活,因为内核驱逐页面的速度快于你的探测周期。运维往往把锅甩给“模型不行”,真正原因却可能是无人值守作业里默认 ulimit -n 只有 256,或是 MCP 工具服务 描述的那类子进程风暴。本篇 2026 指南梳理静默 OOM 的指纹,对照交互式 shell 与 LaunchAgent 的两套 ulimit 世界,给出三条可量化的遥测阈值70% 内存余量、1 万级打开文件、每小时 2GB 级别的换入强度作参照),提供可复制的 SoftResourceLimits plist 片段,并把上限与 并行代理并发健康探测 串起来,让你在用户察觉之前就收到告警。

建议与 部署排障 搭配阅读以完成日志分流;需要按运维手册执行步骤时走 帮助中心。若多次触顶说明是架构瓶颈而非笔误,再用 定价 升级内存档位。

把资源问题讲清楚,本质是帮团队建立共同语言:到底是 FD、RSS、CPU 还是磁盘 I/O 成为第一限制因子。下面各节按“信号—根因—改法”顺序展开,避免你在凌晨三点同时调大三类参数却不知道为什么生效。

在指责模型之前,先记录这些静默 OOM 与限制信号

macOS 统一日志里,jetsam 相关事件常被信息级噪声淹没。若观察到工具延迟 p95 突然放大到 4 倍以上,而 CPU 仍低于 40%,这更像是内存压力而非 LLM 变慢。另一个线索是 MCP stdio 桥在并发尖峰时出现 ENOTFILEToo many open files

  • 压缩器换入:在 16GB mini 上若持续高于 500 MB/小时,说明舒适余量已经不足。
  • LaunchAgent 的 throttleReason 若出现 resource-limits 字样,请把对应 plist 版本纳入 git。
  • 本地网关偶发 502:worker 子进程无法 fork 时常见,多与 RLIMIT_NPROC 相关。

把这些信号写成可查询的标签(机器 region、git commit、模型名、并发度)后,回归分析会快很多;否则你只能凭印象说“昨晚好像卡过”。

launchd 与交互式 shell:两套 ulimit 世界

SSH 会话可能在 ~/.zprofile 里执行 ulimit -n 65535;LaunchAgent 不会自动继承。务必在 plist 实际调用的同一包装脚本里打印限制,而不是在你笔记本的 shell 里打印。

上下文典型 maxfiles谁设置风险
SSH 登录10240+shell rc容易在排查 launchd 时产生误导
LaunchAgent 默认256–1024系统默认MCP 突发很快打满
写入 plist SoftResourceLimits 后8192–65535你的运维团队需与代码侧 FD 卫生策略一致

若你在文档里写“我们已把 ulimit 调到 65535”,请明确指的是哪条执行路径:仅 SSH 生效的说明对无人值守作业没有证据效力。

另一个常见坑是登录项与 LaunchAgent 混用:前者可能继承图形会话的更高配额,后者却在后台以更小默认值启动。把它们画在同一张架构图里,标出“谁拉起 openclaw、父进程是谁、环境变量从哪来”,能避免排障时三个人给出三套互相矛盾的 ulimit -a 截图。

值得把人从床上叫起来的遥测阈值

在现有 健康探测 脚本中,每分钟追加三类数字到 syslog:空闲页文件描述符计数压缩器页。当任意连续两个样本同时越过以下边界,就应该升级告警:

规则包:16GB SKU 上空闲内存低于 2.5 GB、打开 FD 超过 8000、或压缩器页超过 120000——在 24GB 机器上请按内存比例上调。

阈值不是魔法数字,而是把“还能扛”与“已经在悬崖边”分开的刻度。第一次触发建议先自动采集 10 分钟的 samplefootprint 快照,再决定是降并发还是升配。把采样窗口写进值班手册,能避免“只看一眼活动监视器就结案”的草率结论。

Plist 片段:SoftResourceLimits,且别把 launchd fork 炸掉

键必须写在代理字典之下,而不是全局域。保持 hard ≤ soft × 1.25,让错误配置快速失败而不是把系统卡住。

<key>SoftResourceLimits</key> <dict> <key>NumberOfFiles</key><integer>8192</integer> <key>NumberOfProcesses</key><integer>512</integer> <key>Stack</key><integer>8388608</integer> </dict>

仅在保留第二条 SSH 会话的前提下使用 launchctl kickstart -k gui/$(id -u)/com.example.openclaw 重载;纪律可参考 网关重启与恢复

变更 plist 时,建议同时更新变更记录:谁批准、预期 RSS 上限、回滚命令。这样下一次“临时加 limit”不会变成永久技术债。

并发指南 里的每个并行代理都会复制模型句柄与 MCP 套接字。若实验里把并发翻倍带来 3.2 GB RSS 增量,就不要顺手把 NumberOfFiles 也翻倍“以防万一”——那是在掩盖泄漏。更稳妥的是先把并发压在物理内存的 70%(扣除 macOS 基线服务后)以内。

密钥提示:提高 RLIMIT_MEMLOCK 很少能拯救 OpenClaw;请按 密钥加固 使用钥匙串托管秘密,而不是 mmap 巨型缓存。

当你确实需要更高并发时,优先评估模型分片批大小工具调用去抖;把 plist 当作最后手段,而不是第一旋钮。

若你把 RSS 与 FD 曲线对齐观察,往往会看到阶段性相关:FD 尖峰稍后出现,意味着先是连接泄漏,随后才触发内存里的缓冲堆积。此时应先修代码路径,而不是把 NumberOfFiles 一次性拉到极限值,否则下一次事故会在更大的规模上爆炸。

常见问题

若需 8G/16G 档位内存预算、活动监视器与端侧大模型调度,请参阅Mac mini 内存压缩与 Swap 优化指南

是否应以 root 跑 OpenClaw 以获得更高限制? 不建议——应修正 plist;root 只会扩大爆炸半径。

活动监视器够吗? 现场排查可以,但夜间回归要靠自动化的 memory_pressure 日志。

Docker 边车怎么办? 若同机混跑容器,请先把它们的 RSS 从 70% 预算里扣掉。

为何 Apple Silicon Mac mini 仍适合资源密集的 OpenClaw

M4 的统一内存让模型权重与系统服务共享带宽,避免廉价 x86 虚拟机上常见的 PCIe/NUMA 惊喜。按区域租用时,通过 定价 对齐财务预期;当你需要 24 GB SKU 才能撑住更高并发时,升级理由也更好写。原生 launchd 集成优于“Linux 容器假装友好”的那套 systemd 体验。请把 plist 版本与 Git 提交并列记录(参见 GitOps 配置版本化),把本文放进新人入职清单,并在工作负载结束后回收 mini——当金属可预期时,限额也会更好调。

最后一句话留给值日生:任何“提高 limit 就能解决”的结论,都应该附带前后 RSS 曲线截图,否则下周你还会再提一次同样的 MR。

为 OpenClaw 选对硬件规格

香港 / 日本 / 韩国 / 新加坡 / 美国 Mac mini,为自动化留出余量