vscode插件更新不触发自动垃圾回收,旧版本代码驻留内存直至extension host重启或显式卸载;deactivate是唯一受保障的清理入口,必须手动释放资源、注销监听器、清空定时器及动态模块引用。

VSCode 插件更新本身不触发自动垃圾回收,更新后旧版本代码仍驻留内存,直到 Extension Host 进程重启或显式卸载——这是多数人误以为“更新=清理”的根源。
插件更新后内存没降,是因为旧实例没被销毁
VSCode 的 Extension Host 采用进程复用机制:插件更新只是加载新代码模块,但旧模块的引用(如全局变量、未注销的事件监听器、setInterval 定时器)若未在 deactivate 函数中清除,就会持续持有堆内存。V8 不会主动回收这些强引用对象,哪怕新插件已激活。
-
deactivate是唯一受保障的清理入口,必须手动释放所有资源:调用disposable.dispose()、clearInterval()、removeListener() - 动态
import()加载的模块,需缓存其Module引用并在deactivate中设为null,否则模块对象无法被 GC - 使用
vscode.workspace.onDidChangeTextDocument等事件时,务必用context.subscriptions.push()统一管理,避免漏注销
为什么 reload window 不等于 GC?
按 Ctrl+Shift+P → Developer: Reload Window 仅重启渲染进程和 Extension Host 主线程,但不会重置 V8 堆;若插件在 activate 中创建了闭包引用大对象(如缓存整个 AST 树),reload 后该对象仍在堆中,且可能被新旧两个插件实例同时引用。
- 真正有效的 GC 触发点是 Extension Host 进程退出(如完全关闭 VSCode 或禁用插件后重启)
- 可通过
process.memoryUsage().heapUsed在deactivate前后打点,验证是否真有释放 - 对比两次 heap snapshot 中
Closure类型的 Retained Size,若更新后反而增长,说明deactivate逻辑有缺陷
更新期间如何避免内存叠加?
插件市场推送更新时,VSCode 默认启用“后台静默更新”,新版本下载完成即替换磁盘文件,但旧代码仍在内存运行——此时若用户未重启,会出现新旧两套逻辑并存、共享同一份缓存或监听器的危险状态。
- 在
package.json中设置"extensionKind": ["workspace"],强制插件只在工作区激活,避免全局常驻 - 禁用
extensions.autoUpdate(设为false),改用手动更新 + 明确重启流程 - 关键插件(如语言服务器类)应在
deactivate中调用childProcess.kill()清理子进程,防止残留句柄拖累内存
最易被忽略的一点:插件更新日志里写的“修复内存泄漏”,往往只改了新版本逻辑,但老用户不重启,旧泄漏依然存在——清理动作永远依赖 deactivate 执行,而不是更新这个动作本身。











