cc收割机
自动清理会话结束后泄漏内存的孤立克劳德代码进程(子代理、MCP服务器、插件)。
问题
Claude Code为每个会话生成子代理进程和MCP服务器。当会话结束时(尤其是异常情况下),这些进程会成为孤儿(PPID=1),并继续消耗RAM和CPU——通常每个进程消耗200-400MB,有些进程(如Cloudflare的MCP服务器)的CPU消耗达到550%+。如果一天内有多个会话,这可能会累积到7GB以上的浪费内存。
这是一个 广为报道的问题 影响macOS和Linux用户。
什么泄漏
| 工艺类型 | 图案 | 典型尺寸 |
|---|---|---|
| 次级代理商 | claude --output-format stream-json | 每个180-300MB |
| MCP服务器(短期) | npx mcp-server-cloudflare, npm exec mcp-*等等。 | 每个40-110MB |
| 克劳德·梅姆工人 | worker-service.cjs --daemon (面包) | 100 MB |
| 代理浏览器会话 | agent-browser-darwin-arm64Chrome用于测试 agent-browser-chrome-* 配置文件 | 每个100-600 MB |
| Puppeter无头Chrome | Chrome/Chrome助手 puppeteer_dev_chrome_profile-* 配置文件 | 可以连接CPU/GPU |
| 食品法典委员会背景会议 | node /usr/local/bin/codex, @openai/codex/.../codex --yolo | 会话+MCP树 |
|文件描述符|VM进程、settings.json、MCP stdio管道|~6200 FDs/hr泄漏率|
未被杀害:用户应用程序和系统服务,如ChatGPT.app、cmux.app、Bitdefender、Spotlight(mdworker/mds_stores),正常的Chrome浏览和web开发服务器受到保护。跨会话共享的长期运行的MCP服务器(Supabase、Stripe、claude-mem、色度MCP、Cloudflare/顺序思维变体)也受到保护。陈旧的浏览器/Codex清理仅针对孤立的或旧的自动化进程。
解决方案:三层防御
基于PGID的进程组清理由进程管理员和手动工具使用。Stop挂钩默认为 PPID=1孤儿专用清理 为了安全; CC_STOP_HOOK_AGGRESSIVE=1 恢复广泛的PGID组清理。基于模式的检测被保留为边缘情况的后备方案。
Session ends normally
└── Stop hook — primary pass kills orphaned processes (reparented to PID 1, or on Linux to the user's `systemd --user` manager) in session's PGID; secondary pattern sweep catches orphans that escaped the group (e.g., via setsid). With `CC_STOP_HOOK_AGGRESSIVE=1`, skips the orphan-parent check but still protects ancestors and MCP whitelist.
Session crashes / terminal force-closed
└── proc-janitor daemon — scans every 30s, kills orphans after 60s grace
└── OR: LaunchAgent — zero-dependency macOS native, PGID group kill + PPID=1 fallback
Manual intervention needed
└── cc-monitor — explain current CPU heat by process family before cleanup
└── claude-cleanup — finds orphaned PGIDs and stale agent-browser/Puppeteer/Codex stragglers
└── claude-ram — check RAM/CPU usage breakdown with orphan visibility为什么选择PGID?
Claude Code会话是进程组的领导者(PGID=会话PID)。所有生成的MCP服务器、子代理及其子代都继承此PGID。用于工艺管理员和手动工具(claude-cleanup, claude-guard),一个 kill -- -$PGID 可靠地清理组中的所有内容,包括模式匹配可能遗漏的第三方MCP服务器。Stop挂钩默认为更安全的PPID=1孤立模式,以避免意外杀死活动的Claude CLI。
安全:PGID清理仅针对以下组 领导者 是Claude CLI会话(claude.*stream-json).它从不按组成员进行匹配——Chrome和Cursor等其他应用程序 claude 子流程在其流程组中,因此按成员资格匹配会杀死它们。
快速开始
git clone https://github.com/theQuert/cc-reaper.git
cd cc-reaper
chmod +x install.sh
./install.sh正在更新:
git pull
./install.sh安装程序会自动更新钩子和shell函数。对于proc看门人用户,手动同步配置:
cp proc-janitor/config.toml ~/.config/proc-janitor/config.toml
# Edit the log path: replace ~ with your actual home directory手动设置
1.外壳功能
添加 ~/.zshrc 或 ~/.bashrc:
source /path/to/cc-reaper/shell/claude-cleanup.sh
source /path/to/cc-reaper/shell/cc-monitor.sh重新启动后可用的命令:
cc-monitor--在清理之前按进程系列解释当前的CPU热量贡献者(只读)cc-monitor --once--拍摄一个进程快照并立即返回cc-monitor --json--为未来的自动化发出结构化JSONcc-monitor --apply--示例,打印报告,然后发送清理模块(跳过菜单/确认;不能与--json)cc-monitor --no-prompt--禁用TTY上的交互式优化菜单claude-ram--显示RAM/CPU使用率明细,包括每个会话的详细信息和孤立可见性(只读)claude-fd--显示每个会话和VirtualMachine进程的文件描述符使用情况(只读)claude-sessions--列出所有具有空闲检测和进程树RAM的活动会话claude-cleanup--立即终止孤立进程(PGID组终止+模式回退,加上过时的代理浏览器/Pupeteer/Codex清理)claude-guard--自动会话收割器:杀死FD泄漏、臃肿(RSS>阈值)和多余的空闲会话claude-guard --dry-run--预览一下克劳德警卫在没有实际杀人的情况下会杀什么
2.克劳德代码停止挂钩
复制钩子脚本:
mkdir -p ~/.claude/hooks
cp hooks/stop-cleanup-orphans.sh ~/.claude/hooks/
chmod +x ~/.claude/hooks/stop-cleanup-orphans.sh添加 ~/.claude/settings.json 在 "Stop" 挂钩阵列:
{
"type": "command",
"command": "\"$HOME\"/.claude/hooks/stop-cleanup-orphans.sh",
"timeout": 15
}Full settings.json example
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "\"$HOME\"/.claude/hooks/stop-cleanup-orphans.sh",
"timeout": 15
}
]
}
]
}
}⚠️ 安全:止动钩现在包括内置安全机制: - 仅孤儿过滤:默认情况下,只杀死父进程已经退出的进程——那些重新解析为 *孤儿父母*在macOS上,PID为1(launchd);在Linux上,它是PID 1 或调用用户的systemd --user经理 (每个用户的修复目标——Linux孤儿会落在那里,而不是PID 1上)。这是孤儿状态的明确指标——与TTY过滤不同,它在SSH、Docker、tmux和所有终端环境中都能正常工作。活动的Claude会话、子代理和共享MCP服务器(仍由活动进程作为父进程)永远不会被杀死。 - 祖先保护:遍历整个流程树($$→ PID 1),并且永远不会杀死任何祖先进程。这可以防止在涉及中间shell时意外终止Claude CLI。 - 环境变量:参见 止动钩配置 用于调整选项。
3.后台守护程序(选择一个)
选项A:LaunchAgent(零依赖,仅限macOS)
原生macOS方法——不需要Homebrew或Rust。每10分钟运行一次,通过PPID=1检测孤儿。
mkdir -p ~/.cc-reaper/logs
cp launchd/cc-reaper-monitor.sh ~/.cc-reaper/
chmod +x ~/.cc-reaper/cc-reaper-monitor.sh
# Install and replace __HOME__ with actual path
sed "s|__HOME__|$HOME|g" launchd/com.cc-reaper.orphan-monitor.plist \
> ~/Library/LaunchAgents/com.cc-reaper.orphan-monitor.plist
launchctl load ~/Library/LaunchAgents/com.cc-reaper.orphan-monitor.plist有用的命令:
launchctl list | grep cc-reaper # check if running
cat ~/.cc-reaper/logs/monitor.log # view cleanup log
launchctl unload ~/Library/LaunchAgents/com.cc-reaper.orphan-monitor.plist # stop选项B:proc看门人(功能丰富)
基于Rust的守护进程,具有宽限期、白名单和详细的日志记录。需要自制或Cargo。
# Install
brew install jhlee0409/tap/proc-janitor # or: cargo install proc-janitor
# Copy config
mkdir -p ~/.config/proc-janitor
cp proc-janitor/config.toml ~/.config/proc-janitor/config.toml
chmod 600 ~/.config/proc-janitor/config.toml编辑 ~/.config/proc-janitor/config.toml 并替换 ~ 在日志路径中显示您的实际主目录。
启动守护进程:
brew services start jhlee0409/tap/proc-janitor # auto-start on boot
proc-janitor start # or manual有用的命令:
proc-janitor scan # dry run — show orphans without killing
proc-janitor clean # kill detected orphans
proc-janitor status # check daemon health自动会话保护
claude-guard 是一个自动会话收获器,可以防止失控的资源消耗。它分三个阶段运作:
- FD泄漏会话终止 --打开的文件描述符计数超过的会话
CC_MAX_FD立即被杀死。这解决了 广泛报道的FD衰竭问题 其中VM进程泄漏约6200 FD/小时,最终导致系统范围内的“不允许操作”错误。 - Bloated session kill --树RSS(进程+所有子进程)超过的会话
CC_MAX_RSS_MB无论它们是空闲还是活动,都会通过PGID立即杀死。这解决了 约42 GB/hr内存泄漏 由未释放的流式ArrayBuffers引起。 - 空闲会话驱逐 --如果会话计数仍然超过
CC_MAX_SESSIONS,最旧的空闲会话将被终止。
claude-guard # run the guard (kills bloated + excess idle)
claude-guard --dry-run # preview without killing配置
| 变量 | 默认值 | 描述 |
|---|---|---|
CC_MAX_SESSIONS | 3 | 空闲驱逐前允许的最大并发会话数 |
CC_IDLE_THRESHOLD | 1 | CPU%,低于该值的会话被视为空闲 |
CC_MAX_RSS_MB | 4096 | 树RSS阈值(MB);无论活动如何,超过此值的会话都会被终止 |
CC_MAX_FD | 10000 | 文件描述符阈值;超过此值的会话将因FD泄漏而终止 |
CC_AGENT_STALE_MINUTES | 360 | 过时代理浏览器、Puppeter Chrome和分离的Codex/MCP清理的年龄阈值 |
CC_RUNAWAY_CPU | 80 | CPU%,超过此值,受保护进程将被视为卡住/失控(与 CC_RUNAWAY_MIN) |
CC_RUNAWAY_MIN | 60分钟 | 热保护过程被视为失控之前所需的时间 |
CC_RUNAWAY_GRACE_SEC | 5秒 claude-guard 在SIGTERM处理失控的受保护进程之前等待(Ctrl+C中止) | |
CC_RUNAWAY_DISABLE | 0 | 设置为 1 跳过 claude-guard的完全失控阶段 |
示例:降低受约束机器的阈值:
export CC_MAX_RSS_MB=2048
export CC_MAX_FD=5000
export CC_AGENT_STALE_MINUTES=120
claude-guard
claude-cleanupCC_AGENT_STALE_MINUTES 被使用 claude-cleanup 以及LaunchAgent监视器。只有当浏览器自动化经常在您的机器上泄漏时,才降低它;默认值是故意保守的。
止动钩配置
这些环境变量控制着 止动钩 行为。每次吊钩运行时都要检查它们。
| 变量 | 默认值 | 描述 |
|---|---|---|
CC_STOP_HOOK_DISABLE | 0 | 设置为 1 跳过所有清理(钩子变为无操作)。如果钩子干扰了您的工作流程,则很有用。 |
CC_STOP_HOOK_AGGRESSIVE | 0 | 设置为 1 跳过孤儿父级过滤并杀死PGID成员(仍然跳过祖先PID和MCP白名单)。默认情况下,钩子只杀死真正孤立的进程。 |
为什么孤儿父母过滤?
一个过程是 *孤立的* 一旦其原始父级退出,操作系统将对其进行重新配置。macOS将重新配置为PID 1(launchd)。Linux重新修复一个进程,该进程的登录/会话范围已转到调用用户的 systemd --user 经理,而不是PID 1——因此仅PID=1的检查会错过Linux上的每个孤儿。cc收割机制造 孤儿父母组 每次运行一次:PID 1,加上此用户的 systemd --user 管理器(如果存在)(通过UID匹配,因此永远不会包含另一个用户的管理器;管理器PID本身是一个重新分配目标,永远不会是杀死候选对象)。一个过程 PPID 在那一套中,它真的是孤儿,可以安全地收割。未使用TTY筛选,原因如下:
- 在SSH、Docker和远程终端环境中, 全部 进程具有TTY=
?--TTY过滤将是无操作(不杀死任何东西)或危险的(杀死包括Claude CLI在内的所有东西)。 - 在macOS上,孤儿显示TTY=
??在Linux上,它们显示TTY=?--处理这两者都需要特定于平台的代码。 - 孤立父级筛选是 通用的:在macOS、Linux、容器和SSH上工作方式相同。在没有macOS的主机上
systemd --user经理,这套完全正确{1},因此行为不变。
何时禁用停止挂钩:
# Option A: Disable temporarily for the current terminal session
export CC_STOP_HOOK_DISABLE=1
# Option B: Add to ~/.zshrc or ~/.bashrc for permanent disable
echo 'export CC_STOP_HOOK_DISABLE=1' >> ~/.zshrc
# Option C: Remove from settings.json entirely (see manual setup section)何时使用攻击模式:
如果您注意到活动子代理或MCP服务器仍由未清理的垂死会话作为父级(因为父级正在退出过程中,它们的PPID!=1),请启用主动模式:
export CC_STOP_HOOK_AGGRESSIVE=1这将恢复原始的PGID清理,该清理会杀死PGID成员,而不管孤儿状态如何(祖先和MCP白名单仍受保护)。
警告:用户管理的守护进程(LaunchAgent/systemd):
Stop钩子中基于模式的回退也会全局扫描孤立父进程(不限于会话的PGID)。共享MCP服务器受保护 MCP_WHITELIST,但如果在下运行长期守护进程 launchctl /systemd,其命令与其中一种清理模式相匹配,例如无头清理模式 claude --stream-json 工作流或a worker-service.cjs --daemon,无论是由LaunchAgent启动还是由 systemd --user 单位——它是孤儿父母的合法父母,当任何停止钩开火时,它都会被杀死。
如果这适用于您,请选择一个:
# Easiest: disable the Stop hook entirely (other layers — proc-janitor / LaunchAgent — still clean up orphans)
export CC_STOP_HOOK_DISABLE=1
# Or: extend MCP_WHITELIST in hooks/stop-cleanup-orphans.sh to include your daemon's command pattern.热诊断
跑 cc-monitor 当笔记本电脑很热,你想在清洁任何东西之前了解原因时:
cc-monitor # sample for 60s at 5s intervals; progress prints to stderr
cc-monitor --once # immediate snapshot
cc-monitor --json # machine-readable output监视器是只读的。它将进程分为编辑器、cmux、Codex、Claude、MCP、代理浏览器、Chrome、开发服务器、系统等系列。每个发现分为:
| 分类 | 含义 |
|---|---|
SAFE_TO_REAP | 符合现有cc收割机清理标准的陈旧或孤立进程 |
ASK_BEFORE_KILL | 主动用户工具或最近的自动化;停车前检查 |
DO_NOT_KILL | 系统、安全、UI或正常浏览过程 |
JSON输出包括用于自动化的命令字符串,并对常见的令牌/密钥/秘密/密码参数值进行了编辑。
监控后优化
在打印报告之后, cc-monitor 可以分派正确的清理模块,这样您就不必切换命令。
交互模式 (当报告具有以下内容时,默认为TTY SAFE_TO_REAP 候选人或家庭级别的热度):
$ cc-monitor --once
=== cc-monitor: heat attribution ===
... report ...
Optimization options:
1. claude-cleanup (kill all stale orphans) (recommended)
2. claude-guard --dry-run (preview only)
3. proc-janitor scan (preview only)
4. skip
> 1
Run claude-cleanup (kill all stale orphans)? [y/N] y推荐的选项是 claude-cleanup 当存在过时/孤立的候选人时,否则 claude-guard --dry-run 当家族RSS或每进程CPU为高时。当不存在候选人时,菜单将被跳过 --json,当stdin/stdout不是TTY时,或者当 --no-prompt 已通过。二进制文件未打开的模块 PATH 从菜单中隐藏,并在下面列出安装提示。
脚本友好模式 随着 --apply:
cc-monitor --once --apply claude-cleanup # kill stale orphans
cc-monitor --once --apply claude-guard-dry # preview-only
cc-monitor --once --apply proc-janitor-scan # preview-only via daemon--apply 跳过确认提示——该标志本身就是显式的选择加入。它不能与 --json (出口2)。模块退出代码传播。
受阻/失控的受保护进程
长时间运行的MCP服务器、开发服务器和安全守护进程是有意的 protected — claude-cleanup 永远不会杀死他们。但“受保护”并不是绝对的:一个被固定在高CPU上数小时的进程会被破坏,无论其类别如何。
cc-monitor 和 claude-guard 检测 失控的受保护进程 当满足两个阈值时:
- 平均CPU百分比≥
CC_RUNAWAY_CPU(默认值80) - 经过时间≥
CC_RUNAWAY_MIN分钟(默认值60)
cc-monitor 然后对发现进行重新分类 DO_NOT_KILL 致家人 runaway / ASK_BEFORE_KILL,并打印一个专用的“卡住/失控的受保护进程”部分,其中包含一个可粘贴的终止行:
Stuck/runaway protected processes:
PID 9594 node avg 102.70% etime 09:07:51 — protected process appears stuck (sustained high CPU over long elapsed time); review and kill if not actively serving
suggested: kill 9594claude-guard 添加了一个阶段0.5,在PGID感知模式下获取这些PID CC_RUNAWAY_GRACE_SEC (默认5)秒,因此您可以 Ctrl+C 如果报告让你感到意外:
=== Claude Guard ===
Config: max_sessions=3, idle_threshold=1%, max_rss=4096 MB, max_fd=10000, runaway=80%/60min
--- Runaway protected processes (CPU >= 80% for >= 60 min) ---
PID 9594 CPU 102.7% ETIME 09:07:51 node /Users/.../mcp-server-cloudflare run abc
Sending SIGTERM in 5 seconds (Ctrl+C to abort)...
Reaped 1 runaway protected process(es), freed ~340 MB集 CC_RUNAWAY_DISABLE=1 完全跳过失控阶段。JSON消费者在现有数据库中看到失控的条目 findings 数组(带 family: "runaway")加上一个专用 runaway_candidates 阵列。
例子:
=== cc-monitor: heat attribution ===
Sample: once, snapshots: 1
Mode: read-only (no signals sent)
Top contributors:
1. cmux pid 62199 avg 93.00% max 93.00% rss 561 MB ASK_BEFORE_KILL cmux
2. WindowServer pid 384 avg 14.90% max 14.90% rss 128 MB DO_NOT_KILL system
Safe cleanup candidates:
PID 37915 agent-browser avg 0.00% max 0.00% - stale or orphaned browser automation matches cc-reaper cleanup criteria依赖项
| 工具 | 必需 | 安装 |
|---|---|---|
| bash/zsh | 必需 | 预装在macOS/Linux上 |
| macOS LaunchAgent | 选项A(推荐) | 内置,零依赖 |
| 程序管理员 | 选项B | brew install jhlee0409/tap/proc-janitor |
| Claude Code | -- | 此项目清理后的工具 |
文件结构
cc-reaper/
├── install.sh # One-command installer/updater (interactive daemon choice)
├── hooks/
│ └── stop-cleanup-orphans.sh # Claude Code Stop hook (PPID=1 orphan filtering + pattern fallback)
├── launchd/
│ ├── cc-reaper-monitor.sh # LaunchAgent monitor script (PGID + PPID=1 fallback)
│ └── com.cc-reaper.orphan-monitor.plist # LaunchAgent config (10-min interval)
├── proc-janitor/
│ └── config.toml # proc-janitor daemon config (alternative to LaunchAgent)
├── shell/
│ ├── cc-monitor.sh # Read-only heat attribution monitor
│ └── claude-cleanup.sh # Shell functions (claude-ram, claude-fd, claude-cleanup, claude-sessions, claude-guard)
├── tests/
│ ├── agent-process-patterns.sh # Cleanup-candidate matcher validation
│ ├── cc-monitor-optimize.sh # cc-monitor optimization menu tests
│ ├── cc-monitor-runaway.sh # Runaway protected process detection tests
│ └── ppid-fallback.sh # PPID=1 fallback kill + whitelist validation
└── README.md更新日志
看 更改日志.md 版本历史。
相关问题
- 人类学/克劳德编码#20369 --孤立子代理进程泄漏内存
- anthropics/claude代码#22554 --子代理进程未在macOS上终止
- anthropics/claude代码#25545 --空闲时RAM过多
- 多特马克/克劳德成员#650 --worker服务生成不退出的子代理
- 人类学/克劳德编码#29888 --VM过程FD泄漏(~6200/hr)
- 人类学/克劳德编码#28896 --settings.json FD泄漏(每次工具调用1个)
- 人类学/克劳德编码#37482 --MCP服务器stdio管道破裂(孤立FD)
许可证
Apache 2.0
