先建立基线与判断归因
排查的前提是把「感觉卡」变成可观测数据。打开命令面板执行 `Developer: Show Running Extensions`,会列出每个扩展的激活时间与耗时;`Developer: Toggle Performance` 显示键入延迟、渲染时间;`Developer: Show Running Extensions` 之外还有内置的扩展宿主进程监控,能看到 CPU 与内存占用。
区分渲染层与扩展层很关键:如果键入延迟高但 CPU 不在 `Code Helper (Plugin)` 上,多半是渲染器或语言服务(如 TS server)问题;如果某个扩展宿主长期占用高 CPU,几乎可以确定是它。任务管理器里 `Code Helper (Renderer)`、`Code Helper (Plugin)`、`Code Helper (Watcher)` 三个角色的分工要记住:Watcher 专职处理文件监视。
另一个必备动作是用 `code --status` 输出当前会话的进程与内存快照,以及用空窗口复现:`code --disable-extensions .` 打开项目。如果禁用全部扩展后依然卡,问题在编辑器配置、文件数量或工作区本身,而不在扩展。
# 空窗口打开,禁用全部扩展——最直接的归因手段
code --disable-extensions .
# 只跑单个扩展,用于二分定位
code --disable-extensions --locate-extension ms-python.python
# 查看当前会话进程与内存快照
code --status
# 界面内操作
# 命令面板 -> Developer: Show Running Extensions
# 命令面板 -> Developer: Toggle Performance
# 命令面板 -> Developer: Open Extension Host Logs扩展二分定位
扩展数量少(20 个以内)时,逐个禁用最直接。数量多时用二分法:把所有扩展移到临时目录,然后每次放回一半,重复直到定位到单个扩展。二分的价值在于把 N 次测试降到 log2(N) 次,40 个扩展只需 6 轮。
比二分更实用的日常做法是「用三个命令看嫌疑」:`Developer: Show Running Extensions` 里按启动时间排序,最慢的几个优先怀疑;然后对该扩展执行 `Developer: Restart Extension Host` 看卡顿是否消失;再看 `Developer: Open Extension Host Logs` 有没有反复报错或循环。
定位后有三种处置:升级(很多性能问题在扩展新版本已修)、降级锁定版本(团队统一锁住,避免每人不同)、或用 `extensions.json` 里的 `"unwantedExtensions"` 建议禁用。要注意 VS Code 的扩展建议机制不等于强制,用户仍可安装。
// .vscode/extensions.json —— 团队统一扩展集合与禁用建议
{
"recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"],
"unwantedExtensions": [
{
"identifier": {
"id": "some.heavy-extension"
},
"recommendation": "该扩展在大型仓库中显著拖慢启动,请在团队内统一禁用"
}
]
}
// 二分定位脚本骨架(Bash)
// 1) 备份当前扩展目录
// 2) 循环:恢复一半扩展 -> code --disable-extensions . 复现 -> 记录卡顿程度files.exclude 与 search.exclude:控制索引与搜索范围
这两个设置常被混淆,职责不同:`files.exclude` 决定哪些文件不出现在文件树与资源管理器的搜索中;`search.exclude` 决定哪些文件在执行搜索时被跳过。用 glob 模式(而不是路径模式)可以更精确地按文件名或扩展名过滤。
真正影响性能的是默认配置里那些被隐式排除的目录:`.git`、`node_modules`、`dist`、`build`、`.next`、`target`、`vendor`。VS Code 默认排除了一些,但一旦你在工作区里做 `Add Folder to Workspace` 或引入 monorepo 结构,默认值往往不够,需要显式补充。
合理的配置原则是:把生成物目录排除出文件树(减少文件监视与资源管理器渲染压力),把超大二进制目录排除出搜索(避免搜索时一次性读取海量内容)。同时配合 `search.useIgnoreFiles: true` 与 `search.useGlobalIgnoreFiles: true` 让 `.gitignore` 与 `.ignore` 生效,通常这一项就能解决大部分搜索卡顿。
// settings.json
{
"files.exclude": {
"**/.git": true,
"**/node_modules": true,
"**/dist": true,
"**/build": true,
"**/.next": true,
"**/target": true,
"**/.venv": true,
"**/*.log": true
},
"search.exclude": {
"**/node_modules": true,
"**/dist": true,
"**/build": true,
"**/target": true,
"**/*.min.js": true,
"**/*.map": true,
"**/pnpm-lock.yaml": true
},
"search.useIgnoreFiles": true,
"search.useGlobalIgnoreFiles": true,
"search.smartCase": true
}大仓库的索引与文件监视调优
在超过几十万文件的仓库里,文件监视(watcher)会吃满 inode 和 CPU。Linux 上最有效的三招是:把 `files.watcherExclude` 指向生成物目录、启用原生递归监视(`files.watcherUsePolling: false`,多数场景不要开轮询),以及在容器/网络盘上改用 gVisor 类文件系统以减少 inode 事件。
TypeScript 项目要单独处理 `tsserver` 的内存与文件数:`typescript.tsserver.maxTsServerMemory: 4096` 提高内存上限,`typescript.disableAutomaticTypeAcquisition: true` 关闭自动类型获取(会额外拉取 `@types` 并触发二次索引),`typescript.tsserver.useSyntaxServer` 可只启用轻量语法服务器。
编辑器层面还有两个常被忽略的开关:`editor.codeLens: false` 与 `editor.minimap.enabled: false` 能明显降低大文件渲染压力;`files.hotExit` 保持默认开启,避免关窗时序列化未保存状态造成假卡顿。改完设置后执行一次 `Developer: Reload Window` 让索引重建,再对比 `Developer: Toggle Performance` 的读数。
// 大仓库 settings.json
{
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/node_modules/**": true,
"**/dist/**": true,
"**/build/**": true,
"**/.next/**": true
},
"files.watcherUsePolling": false,
"typescript.tsserver.maxTsServerMemory": 4096,
"typescript.disableAutomaticTypeAcquisition": true,
"editor.codeLens": false,
"editor.minimap.enabled": false,
"files.hotExit": "onExitOnly",
"search.followSymlinks": false
}