vscode debug golang 代码不按顺序跳转、变量不可见问题

解决使用 vscode 调试 golang 项目时,偶遇的代码不按顺序跳转以及部分变量不可见的问题

问题描述

使用 vscode 调试 golang 项目时,发现部分代码不按顺序跳转,变量不可见。

img.png

launch.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "debug ae app",
      "type": "go",
      "request": "launch",
      "mode": "exec",
      "program": "${workspaceFolder}/ae-app-598",
      "preLaunchTask": "build.ae.app"
    }
  ]
}

task.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "build.ae.app",
      "type": "shell",
      "command": "make generate && make build"
    }
  ]
}

排查

google 搜索相关词条后,初步定位是 gcflags 参数问题,在 launch.json 中添加 "buildFlags": "-gcflags=all=-N -l" 参数后问题仍然复现,且 debug 会触发 vscode 提示。

img_1.png

提示链接 https://github.com/golang/vscode-go/blob/master/docs/debugging.md#debugging

根据 gcflags 关键词查找到相关内容

img_2.png

必须使用 go build -gcflags=all="-N -l" 构建二进制文件以禁用可能干扰调试的内联和优化。

解决

排查makefile 文件,发现 include 子文件中 go build 命令没有带 -gcflags=all="-N -l" 参数。

img_3.png

添加参数后问题解决

img_4.png

img_6.png

关于 buildFlags

-gcflags="all=-N -l" 是 Go 编译器的一个常见调试选项,用于控制 Go 编译器优化行为,主要目的是禁用优化和内联,从而使生成的代码更适合调试。

参数解释

-gcflags

  • 全称:Go Compiler Flags
  • 作用:用于传递给 Go 编译器的标志,影响编译过程的行为。
  • 格式-gcflags='pattern=flags'
    • pattern 指定应用这些标志的包(例如 main./...all)。
    • flags 是具体的编译器参数。

all

  • 作用:表示这些编译标志将应用于所有包(包括标准库和项目代码)。
  • 示例
    • -gcflags=all=-N -l:对所有包禁用优化和内联。
    • -gcflags=main=-N:只对 main 包禁用优化。

-N

  • 作用:禁用优化。
  • 详细说明
    • 在调试中,禁用优化有助于让生成的代码更接近于源代码。
    • 优化关闭后,变量的值和执行路径更容易在调试器中被准确跟踪。

-l

  • 作用:禁用函数内联(Inlining)。
  • 详细说明
    • 函数内联是编译器将一个函数的调用替换为该函数的代码,从而提升运行时性能。
    • 在调试中,内联可能导致函数调用栈不准确,变量信息丢失等问题。
    • 禁用内联可以保留函数调用栈的完整性。

综合效果

当使用 -gcflags="all=-N -l"

  1. 优化禁用:编译器不再优化代码,源代码与生成的机器码保持较高的一致性。
  2. 内联禁用:函数的调用关系在运行时完全保留,便于调试器追踪调用栈和变量信息。

使用场景

  1. 调试

    • 开启调试器(如 dlv)时,为了能更准确地显示变量值和调用栈。
    • 示例:
      1
      2
      
      go build -gcflags="all=-N -l"
      dlv exec ./your_program
      
  2. 定位问题

    • 如果程序行为异常且难以调试,通过禁用优化和内联来简化调试过程。
  3. 性能分析对比

    • 使用禁用优化的版本对比优化后的版本,分析优化对性能的影响。

注意事项

  1. 性能影响

    • 禁用优化和内联后,生成的代码运行速度会变慢,特别是在大规模项目中。
    • 不建议在生产环境中使用。
  2. 限制性

    • 这些标志仅对编译的包有效,对预编译的标准库(如 fmtnet)无效,除非重新编译标准库。
    • 重新编译标准库:
      1
      
      go install -a -gcflags="all=-N -l" std
      

示例

1
2
3
4
5
6
7
8
# 对当前项目禁用优化和内联
go build -gcflags="all=-N -l"

# 对特定包禁用优化(如 `mypkg`)
go build -gcflags="mypkg=-N -l" ./mypkg

# 使用 Makefile 构建时禁用优化
make build GCFLAGS="all=-N -l"
本博客已稳定运行 小时 分钟
共发表 31 篇文章 · 总计 82.93 k 字
本站总访问量
Built with Hugo
主题 StackJimmy 设计