确认句柄泄漏需查系统级inotify耗尽(如inotifywait报“no space left on device”)和exthost空载后rss不降;vscode中用developer: open process explorer定位高内存+高cpu插件,配合files.watcherexclude配置与code --disable-extensions验证。

插件更新后出现大量句柄泄漏,大概率是它在 fs.watch 或 chokidar.watch 里没关监听器,或者监听范围失控了。
怎么确认是不是句柄泄漏而不是普通内存涨
别只看任务管理器里“Code Helper”数字——那混着渲染进程、GPU 进程,根本分不清。真实句柄泄漏的表现是:exthost 进程 RSS 内存不回落,且系统级 inotify 句柄耗尽。
- Linux/macOS 下运行
inotifywait -m -r . 2>&1 | head -n 20,如果立刻报No space left on device,说明内核 inotify 已满 - 查当前上限:
cat /proc/sys/fs/inotify/max_user_watches,≤ 16384 就大概率是瓶颈 - VSCode 里按
Ctrl+Shift+P→ 执行Developer: Open Process Explorer,展开extensionHost节点,看哪个插件在空载(关闭所有文件)后仍占高内存 + 高 CPU
哪些插件更新后最容易触发句柄泄漏
不是所有插件都危险,但以下几类更新后高频出事:
- 带文件监听功能的语言服务器:比如
rust-analyzer、pylsp、intelephense,新版可能默认开启递归监听整个工作区 - Git 相关插件:如
GitLens,更新后可能新增对.git/refs或.git/logs的持续 watch - 本地构建/打包插件:比如
ESLint或Prettier的 VSCode 封装版,若监听逻辑写在onDidOpenTextDocument里又没配对.close(),每次打开文件就多一堆句柄
快速定位泄漏插件并临时止损
禁用插件后不重启 exthost,泄漏状态不会释放——这是很多人卡住的关键点。
- 先进安全模式:
code --disable-extensions,确认是否还崩;若稳定,说明确实是插件问题 - 打开命令面板,执行
Extensions: Disable All Installed Extensions,再逐个启用,每启一个就跑一次ls /proc/$(pgrep -f "extensionHost")/fd | wc -l看 fd 数是否跳变 - 发现嫌疑插件后,立刻加配置限制监听范围:在工作区
.vscode/settings.json中加"files.watcherExclude": { "**/node_modules/**": true, "**/dist/**": true, "**/.git/**": true },然后重启窗口 - 若该插件开源,可直接搜其源码里的
fs.watch(或chokidar.watch(,重点检查有没有漏掉.close(),尤其在deactivate()或错误分支里
修复前必须验证的两个细节
很多修复方案失效,是因为忽略了这两件事:
-
recursive: true在 Windows 上对目录重命名不触发事件,跨平台项目建议统一换chokidar,它内部做了兜底轮询和句柄复用 - 插件若在
webview里调用了fs.watch(比如嵌入式文件浏览器),必须确保webview.dispose()后显式调用watcher.close(),否则闭包捕获的 watcher 实例无法被 GC











