租用 Mac mini 上的 OpenClaw MCP 子程序殘留:退出衛生與 launchd 回收實務(2026-05-19)
若你在 ProxyMac 香港、日本、韓國、新加坡或美國 節點租用的 Mac mini M4 上同時執行 OpenClaw 與 Model Context Protocol(MCP)stdio 工具,卻遇到閒置時 RSS 仍持續上升、node 程序數量異常、或閘道升級後工具呼叫「偶發卡死」,本篇提供可複現的排障路徑:先區分孤兒程序堆疊與JSON 行緩衝卡死,再以五欄決策矩陣對齊訊號與動作,最後執行九步對 launchd 友善的清理。文中與 並行代理並發、stdio 行緩衝、閘道重啟恢復 互相連結,方便嵌入值班手冊。
症狀:在換頁抖動之前就看得到的「程序漂移」
社群與上游議題已有案例:某些 CLI/MCP 組合在父程序結束後仍長期占用記憶體,單一 Node 子程序可能穩定持有數十 MB 級別的常駐集(RSS)。單租戶實體機不像共享容器替你遮掩,問題會直接反映在 top、磁碟 I/O 與 launchd 的 CPU 配額上。
- 程序列表漂移:徹夜無人 SSH,但
pgrep -lf mcp/pgrep -lf modelcontextprotocol行數比冷啟動後明顯更多。 - 工具延遲階梯化:首批呼叫成功,後續排隊;根因常是某條管道讀端未收到 EOF,因仍有殭屍讀者占著 stdin。
- 版本錯位:本機 CLI 已升級,而舊閘道仍監督舊 semver 拉起的子樹,訊號語意與預期不一致。
- 誤判「模型掛了」:供應商延遲正常,但本機 fork 壓力飆升;務必先查本機再歸咎 LLM。
根因:為什麼 stdio MCP 容易留下「黏性子樹」
stdio 方案避免任意暴露 TCP 埠,但承襲 POSIX 語意:只要寫端未關閉,讀端就永遠等不到 EOF;npx 類引導器亦可能留下脫離中繼 shell 的孫程序。OpenClaw 跑在 LaunchAgent 下時,環境比筆電互動 shell 更「瘦」——HOME、PATH 與鑰匙圈脈絡若不一致,子程序可能在短循環重啟裡自我繁殖,看起來像攻擊排程器,其實只是自動化腳本的邊界條件。
再搭配 ulimit 與記憶體上限:許多 macOS 工作負載上單程序軟限制 2560 個檔案描述子聽起來寬裕,但當並發工具呼叫把「每呼叫 × 三根管道」的乘法做起來,中途觸頂就會留下半開描述子,為 MCP 兄弟程序並存創造條件。
現場處置矩陣(訊號 → 動作)
| 首要訊號 | 第一反應(順序敏感) | 必須留存的資料 | 誤判回滾 | 升級負責人 |
|---|---|---|---|---|
| 20 分鐘內 RSS 無故上漲約 200 MB | 先 ps -o pid,ppid,rss,command 快照,再談重啟 | PPID 鏈 CSV + JSONL 時間戳 | 未標示父 PID 前勿批量 kickstart | 平台 SRE |
| 管理埠(如 18999)出現雙監聽 | 依 閘道恢復 單一監聽檢查表執行 | lsof -nP -iTCP:18999 -sTCP:LISTEN | 若兩枚 plist 互搶,bootout 錯誤標籤 | 自動化負責人 |
| 429 風暴但本機 CPU 不高 | 先降並發,參考 並行代理指南 | 每 5 分鐘桶的 429 計數 | 還原舊的 maxConcurrentTasks | FinOps + 演算法 |
| RSS 平穩但工具卡死 | 優先查緩衝/PTY,而非 SIGKILL 日 | 取樣級系統呼叫日誌(政策允許時) | 撤銷無緩衝實驗參數 | 用戶端工程 |
九步清理手冊(SSH 登入 ProxyMac mini)
- 廣播維護窗口:哪怕只回收 90 秒,也要避免 CI 靜默踩雷。
- 匯出證據:閘道日誌尾部 500 行 +
launchctl print gui/$UID過濾 OpenClaw 相關 label。 - 凍結新任務:暫停排程或 Webhook 入口,避免「邊殺邊生」。
- 標示父程序:畫清 PPID;在子程序分類完成前,不要對 launchd 託管的閘道直接
kill -9。 - TERM 波:對確認的 MCP 葉程序送 SIGTERM,等待 15 秒再計數。
- KILL 只給已驗證 argv 的頑固分子。
- 回收閘道:使用廠商文件支援的
launchctl kickstart -k或 bootout/bootstrap 組合。 - 冒煙:以唯讀工具連續呼叫 兩次,觀察 10 分鐘內 RSS 是否回到基線。
- 復盤工單:若每週復發,附上 PPID CSV 並連結本文,推動設定層修復。
launchd 視角:回收紀律與 ThrottleInterval
LaunchAgent 不是 systemd:ThrottleInterval、KeepAlive、SuccessfulExit 會共同決定 macOS 以多激進策略 respawn 閘道。若只重啟 Node 二進位卻遺留舊 stdio 控點掛在失效 PTY 上,launchd 仍會認為閘道「健康」,工具側卻隨機連到半死管道。任何手動 kill 後,都要用 launchctl print 對齊 plist,並確認 EffectiveUserID 與 ~/Library/LaunchAgents 擁有者一致。
若每次大版本需一次性點 TCC/鑰匙圈授權,可短期使用 VNC 完成 GUI 步驟,再回到 說明中心 所述的無頭 SSH 流程——把 GUI 審批與無人值守 launchd 週期混在同一台機器上,最容易把 MCP 伺服器拉起兩份。
預防:並發、逾時與爆炸半徑
治理孤兒比事後殺程序便宜:
- 把並行工具呼叫壓在拐點之前,佇列心智模型見 並行 OpenClaw。
- 為每個 MCP server 設定硬逾時(鍵名隨發行版不同):網路型工具可先以 120 秒 為上限,唯讀檔案 stat 可嘗試 15 秒 量級。
- 每個自動化身分獨立工作目錄,避免多代理爭用
git與套件管理員鎖。 - 實驗性 MCP 與正式編排分機器——HK/JP/KR/SG/US 多區域讓「加一台沙盒 mini」變成定價頁勾選,而不是先買硬體再後悔。
常見問題
為什麼閘道停了,MCP stdio 程序還在? 閘道異常結束、SIGTERM 未層層傳遞到孫程序,或 npx 啟動的中繼 shell 已結束但 Node 孫程序仍存活,都會留下半連線 MCP。launchd 若依 KeepAlive 立刻拉起新閘道,舊管道仍被占用時,就會出現工具隨機卡住而模型延遲正常的假象。
正式環境可以直接 kill 疑似 MCP 孤兒嗎? 先 SIGTERM 並保留 ps/lsof 證據,確認命令列與 argv 屬於 MCP 工具後再考慮 SIGKILL。共享自動化主機上務必核對開啟檔案,避免誤殺同事連線。清理後依廠商 LaunchAgent 流程重啟閘道,並以 lsof 確認管理埠僅有一個監聽程序。
這與 stdio 行緩衝卡死有何不同? 行緩衝問題常表現為 JSON 片段遲遲不完整、CPU 並未飆升;孤兒堆疊則常見 RSS 單調上升與多餘 node 程序。前者優先查 PTY/無緩衝參數,後者要收緊並發、逾時與閘道回收紀律。
為什麼把 MCP 副作用 containment 放在 ProxyMac Mac mini 上更划算
MCP 放大了作業系統面:每次工具呼叫都是一次 fork、一組 fd、一次訊號傳播機會。Apple Silicon M4 在單執行緒與能效上給 stdio 多程序留足餘量;macOS 與桌面腳本堆疊一致;香港/日本/韓國/新加坡/美國 節點選擇讓你把自動化放在離 SaaS 與登錄檔更近的位置。ProxyMac 的租賃模型意味著你可以為高風險 MCP 整合另外開一台可犧牲的沙盒 mini,用同一張 定價 頁面說服利害關係人,把機器回收當作軟體衛生的一部分,而不是先買硬體再後悔。