PAYATHON 2026

Ubuntu 更新后 VS Code 调试启动缓慢,如何优化库调试符号加载?

排障赵师傅

可以先在 launch.json 中限制共享库符号的自动加载。如果延迟来自 GDB 下载调试信息,再关闭 debuginfod。两项设置要分开测试,才能判断时间花在哪里。

现有日志只表明调试器报告了这些库的符号加载,无法证明 12 秒全花在这四个库上,也不足以认定问题是某次 Ubuntu 更新引入的缺陷。

为什么 hello world 也会慢?

即使程序很小,C++ 程序通常也会加载 libstdc++、libc 等共享库。GDB 除了读取程序自身的调试信息,还可能查找和读取这些库的独立调试符号。启用 debuginfod 后,它还可能通过网络获取缺失的信息。

所以,减少源代码不一定能缩短这部分时间。每次启动调试通常都会启动新的 GDB 进程,上一个进程已经解析的符号不会直接保留到下一次。磁盘缓存或下载缓存可能有帮助,但后续启动不一定更快。

题目中的 -O0 -g 适合调试自己的代码,暂时不用改。删除 -g 会丢失自己的源码调试信息,也不能直接解决系统库符号加载的问题。

先限制共享库符号加载

如果平时只调试自己的可执行文件,可以在 cppdbg 配置中加入:

"symbolLoadInfo": {
    "loadAll": false
}

完整配置可以写成:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Debug",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/build/x86_64-linux-gnu/Debug/sandbox_cpp.bin",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "miDebuggerPath": "/usr/bin/gdb",
            "symbolLoadInfo": {
                "loadAll": false
            },
            "setupCommands": [
                {
                    "description": "Enable pretty printing",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "build"
        }
    ]
}

symbolLoadInfo 控制共享库符号的加载,不会关闭主可执行文件自身的调试信息。编译时保留 -g,仍然可以调试 main.cpp 中的代码。

如果还要调试自己编写的共享库,可以把它加入例外列表。假设库名是 libsandbox.so:

"symbolLoadInfo": {
    "loadAll": false,
    "exceptionList": "libsandbox.so"
}

当 loadAll 为 false 时,exceptionList 指定需要加载符号的库。多个名称用分号分隔,也可以使用通配符。

如果只想排除题目中的四个库,保留其他库的符号加载,可以改为:

"symbolLoadInfo": {
    "loadAll": true,
    "exceptionList": "libstdc++.so.6;libc.so.6;libm.so.6;libgcc_s.so.1"
}

当 loadAll 为 true 时,例外列表指定的是不加载符号的库。两种配置选一种即可。

如果仍然慢,检查 debuginfod

只有 GDB 支持并启用了 debuginfod,而且启动时确实发生了远程查询,关闭它才可能缩短等待时间。如果问题出现在系统更新后,可以检查这个方向,但仅凭出现问题的时间还不能确定原因。

先在终端启动 GDB:

gdb -q ./build/x86_64-linux-gnu/Debug/sandbox_cpp.bin

查询当前设置:

(gdb) show debuginfod enabled

然后在新的调试会话中关闭它,再运行到 main:

(gdb) set debuginfod enabled off
(gdb) start

将耗时与默认设置下执行 start 的耗时比较。如果关闭后明显变快,可以把下面的对象加入现有的 setupCommands 数组:

{
    "description": "Disable debuginfod",
    "text": "-gdb-set debuginfod enabled off",
    "ignoreFailures": false
}

关闭后,GDB 不再通过 debuginfod 自动获取缺失的调试信息,本地已有的调试符号仍然可用。如果 GDB 提示不认识该命令,说明当前版本或构建不支持这一设置。删除该项,继续排查其他原因。

测试 debuginfod 时,应暂时恢复原来的共享库符号加载设置。如果已经跳过共享库符号,远程查询造成的延迟可能会被掩盖。

两项配置都无效时,继续定位耗时

  1. 在终端直接用 GDB 调试同一个可执行文件,比较运行到 main 的时间。
  2. 如果终端同样慢,重点检查 GDB 的符号读取、启动脚本和自动加载脚本。
  3. 如果终端很快,而 VS Code 仍然慢,在 launch.json 的调试配置中临时加入日志设置:
"logging": {
    "engineLogging": true
}

重新启动调试,查看 Debug Console 中最后发送的命令及其返回信息,留意明显停顿的位置。排查完成后删除该设置,避免产生过多日志。

Loaded ... Symbols loaded. 是状态信息,本身不包含耗时,单靠它无法判断瓶颈。题目已说明 make 几乎立即结束,因此可以先保留 preLaunchTask,重点排查调试器初始化阶段。

使用时需要注意什么?

限制共享库符号加载后,进入标准库或系统库查看源码、设置源码断点、检查库内部变量等操作会受影响。需要排查这些库内部的问题时,应恢复对应库的符号加载。

动态符号等信息可能仍然可用,因此调用栈中还可能出现部分库函数名。看到函数名,并不代表完整调试信息已经加载。

这些配置可以减少不必要的符号处理。具体能节省多少时间,需要在本机比较,无法保证把题目中的 12 秒降到某个固定值。

备注:内容仅供参考。