直接按Ctrl+Shift+I打开DevTools,切到Memory面板点击Take heap snapshot;需在卡顿未消失时抓取,避免GC回收后误判,重点关注ExtensionHost闭包、String/Array占比过高及重复DocumentModel,并通过Retainers追溯泄漏链。

怎么打开 DevTools 并抓内存快照
直接按 Help → Toggle Developer Tools(或 Ctrl+Shift+I / Cmd+Option+I),切换到 Memory 面板,点 Take heap snapshot 即可。注意:必须在编辑器处于“卡顿但没崩溃”状态时抓,否则快照反映的是常态而非瓶颈。
常见错误是等卡顿消失后再截图——此时 GC 已回收,关键泄漏对象早已被清掉。建议在输入卡顿、补全延迟明显时立即操作。
怎么看快照里谁在吃内存
快照生成后,默认按 Constructor 排序,重点关注以下几类:
-
ExtensionHost下的闭包或Module实例:说明某个插件缓存了大量未释放的数据(比如 Auto Import 会持久化 AST 节点引用) -
String或Array占比异常高(>30%):可能是日志缓冲区未清理,或搜索结果缓存未设上限 - 重复出现的
DocumentModel或TextModel:表示编辑器未正确卸载已关闭文件的模型(多见于 Markdown 预览或自定义语言插件)
点击某构造函数,右侧的 Retainers 标签能告诉你“谁还拿着这个对象”,这是定位泄漏链的关键入口。
为什么 snapshot 对比没用,以及怎么避免
直接对比两个快照(如“启动后” vs “卡顿后”)容易误判,因为:
- V8 的 GC 行为不可控,两次快照间可能触发不同轮次回收
- 扩展宿主进程会动态加载/卸载模块,
retained size波动大 - 真正的问题常藏在“增长最猛的一类对象”,而不是总量最大的一类
更可靠的做法是:连续抓 3 个快照(间隔 10 秒),观察 Objects allocated between snapshots —— 这里列出的是新增且未被 GC 的对象,才是真正可疑的泄漏源。
哪些配置会让快照分析失效
以下设置会干扰堆快照准确性,排查前务必检查:
-
"telemetry.enableTelemetry": true:遥测模块持续上报数据,产生大量临时字符串和事件对象 -
"search.followSymlinks": true:符号链接循环导致快照中出现冗余FileSystemWatcher实例 -
"editor.largeFileOptimizations": false:大文件未启用流式解析,快照里塞满整块Uint8Array缓冲区
抓快照前建议临时加一行:"developer:showDevTools": true 到 settings.json,确保 DevTools 界面本身不被优化掉。
Retainers 往上翻 5–6 层,找到那个没被 dispose() 的监听器或没被 clearTimeout() 的定时器——这些细节往往藏在扩展源码深处,而不是你自己的代码里。



















