前言¶
在 Windows 上跑 DSH,每次 shell 调用都会拉起一个私有 runner 进程。命令跑完,这个 runner 本该自己退出,但实测它经常留下来:README 记录的一台 DSH Desktop 0.2.x 上,一个工作会话里攒了 8 个,占 1127 MB,最老的一个已经空转了四个半小时。@deepseek-ai/dsh-subprocess-local 和 dsh-ops 都没有暴露 shell 生命周期的设置项,也就是说没什么可配置的。cg-shell-janitor 就是针对这个问题的绕开方案,由 DonGeeo87 维护,分类是 admin-security。
下面介绍它的工作方式、配置项和安装方法。
问题出在哪¶
Windows 上每次 dsh shell 调用都会启动一个私有 runner:
"DeepSeek Harness.exe" "...\dsh-subprocess-local\lib\runner.js" -- ...\bash.exe -c "<your command>"
这个 runner 持有命令的 Win32 Job。命令结束时它理应通过自己的 poll() 关闭空 Job 并调用 finish(0),实际却常常继续存活,持续占着内存。这正是 cg-shell-janitor 要清理的对象。
核心功能¶
插件每 intervalSeconds 采样一次,查找 DSH runner 进程,关闭其中确实无事可干的。关闭 runner 会释放它持有的 Win32 Job,这与 DSH 自己管理子进程的语义一致。它只在以下条件全部满足时才动手:
- runner 的父进程仍然是 DSH host 进程。
- runner 没有活着的子进程,也就是
bash.exe已经退出。 - 它曾经被观察到的子进程也没有还活着的,说明它没有在照看后台进程。树在每次采样时重新学习,所以用
&留下一个 server 的那条命令,它的 runner 仍受保护。 - 它存在的时间超过
idleMinutes。 - 周围没有无法归因的类 daemon 孤儿进程。如果有,插件进入保守模式,本轮什么都不关。
启动后的第一次采样只观察,不决定,先摸清当前进程树。插件不删除任何文件,除了泄漏的 runner 本身,不碰任何进程。
README 给出的实测数据来自同一台机器、同一会话,第一次真实周期之后:存活 runner 从 8 个(1127 MB)降到 2 个(288 MB,两个都有正在跑的 shell),空闲内存从 3.37 GB 升到 5.78 GB,总进程数从 298 降到 240。
安装¶
README 提到两种途径:从 dsh-market 目录一键安装,或者从本地 checkout 安装。本地安装命令是:
dsh plugin --profile <your-profile> add <path-to-this-directory>
完成后重启 harness。
卸载命令:
dsh plugin --profile <your-profile> remove cg-shell-janitor
配置¶
配置写在 cordis.patch.yml 里:
| Key | 默认值 | 含义 |
|---|---|---|
enabled |
true |
关闭周期但不卸载插件 |
dryRun |
false |
只记录将要关闭的进程,不做实际操作 |
intervalSeconds |
180 |
采样间隔(取值 30–3600) |
idleMinutes |
5 |
关闭前的最短存活时长(取值 1–1440) |
reapOnStartup |
true |
启动后 20 秒做第一次采样 |
一个周期大约每三分钟占用单核 2 秒,因为只通过 PowerShell 跑一次 Get-CimInstance 查询。如果这对你来说也有影响,把 intervalSeconds 调大即可。
日志写在 ~/.dsh/shell-janitor.log,按 256 KB 轮转。
适用场景与注意¶
面向在 Windows 上长时间使用 DSH、被泄漏 runner 累积占内存困扰的开发者。需要留意几点:
- 仅限 Windows。 泄漏出在持有 Win32 Job 的 runner 上,其他平台上插件只记一行日志不做任何事。
- 这是一个启发式方案,不是修复。真正的修复在上游:runner 本该自己退出。
- 插件加载前已创建、且 shell 已经退出的 runner,在插件侧没有子进程记录。它一旦超过
idleMinutes仍会被关闭,因为条件 5 只拦那些插件完全无法归因的孤儿进程。 - 如果你刻意从 shell 命令里保活一个 daemon,而插件从未观察到那条命令,这个 daemon 只受保守模式保护,而不是精确匹配保护。
插件以当前 dsh 进程的权限运行,安装前建议先查看它的源码(README 和 cordis.patch.yml)并确认许可证:MIT。
小结¶
cg-shell-janitor 做的事情很窄:周期性找出 Windows 上已经无事可做却没退出的 DSH runner 并关掉,单个约能回收 140 MB。它不能替代上游修复,但在配置项缺位的情况下提供了可用的清理手段。
- 社区目录页:https://www.skillhub.cn/plugins/DonGeeo87/cg-shell-janitor
- GitHub:https://github.com/DonGeeo87/cg-shell-janitor