Go 1.12 生产环境下代码调试改进
大卫·蔡斯
2019年3月21日
介绍
Go 1.11和Go 1.12在允许开发人员调试部署到生产中的相同优化二进制文件方面取得了重大进展。
随着Go编译器在生产更快的二进制文件方面变得越来越激进,我们在可调试性方面已经失去了基础。在Go 1.10中,用户需要完全禁用优化功能才能从诸如Delve之类的交互式工具获得良好的调试体验。但是用户不必为了可调试性而牺牲性能,尤其是在运行生产服务时。如果您的问题出在生产中,则需要在生产中进行调试,而这不需要部署未优化的二进制文件。
对于Go 1.11和1.12,我们专注于改进优化二进制文件(Go编译器的默认设置)的调试体验。改进包括
-更准确的值检查,尤其是函数输入时的参数检查;
-更精确地标识语句边界,从而使步伐不那么跳跃,断点更多地落在程序员期望的位置;
-并初步支持Delve调用Go函数(与C和C ++相比,goroutines和垃圾回收使此过程更加棘手)。
使用Delve调试优化的代码
Delve是x86上Go的调试器,同时支持Linux和macOS。 Delve知道goroutines和其他Go功能,并提供了最佳的Go调试体验之一。 Delve还是GoLand,VS Code和[Vim](https:// /github.com/fatih/vim-go)。
Delve通常使用-gcflags“ all = -N -l”
重建正在调试的代码,这将禁用内联和大多数优化。要使用delve调试优化的代码,请先构建优化的二进制文件,然后使用dlv exec your_program
对其进行调试。或者,如果您从崩溃中获取核心文件,则可以使用dlv core your_program your_core
对其进行检查。使用1.12和最新的Delve版本,即使在优化的二进制文件中,您也应该能够检查许多变量。
改进价值检查
当调试Go 1.10生成的优化二进制文件时,变量值通常完全不可用。相反,从Go 1.11开始,通常甚至可以在优化的二进制文件中检查变量,除非对它们进行了完全的优化。在Go 1.11中,编译器开始发出DWARF位置列表,因此调试器可以跟踪变量在寄存器中移入和移出的过程,并重建分散在不同寄存器和堆栈插槽中的复杂对象。
改进了步进
该示例显示了在1.10版本的调试器中逐步执行简单功能的示例,其中的缺陷(跳过的和重复的行)用红色箭头突出显示。
这样的缺陷使您很容易在单步执行程序时失去对您的位置的跟踪,并干扰达到断点。
1.11和1.12记录语句边界信息,并通过优化和内联更好地跟踪源行号。结果,在Go 1.12中,逐步执行此代码会在每一行上停止,并按您期望的顺序执行。
函数调用
Delve中的函数调用支持仍在开发中,但简单的案例仍然有效。例如:
(dlv)致电fib(6)
> main.main()./hello.go:15(PC:0x49d648)
返回值:
〜r1:8
前进的道路
Go 1.12是朝着优化二进制文件的更好调试体验迈出的一步,我们计划进一步改进它。
可调试性和性能之间需要进行基本的权衡,因此我们将重点放在优先级最高的调试缺陷上,并努力收集自动化指标来监控我们的进度并捕获回归。
我们专注于为调试器生成有关变量位置的正确信息,因此,如果可以打印变量,则可以正确打印。我们也在寻找更多时间使用变量值的方法,尤其是在呼叫站点之类的关键点,尽管在许多情况下要改善此值可能会减慢程序的执行速度。最后,我们正在努力改善步进:我们着眼于恐慌的步进顺序,循环的步进顺序,并尽可能地遵循源顺序。
关于macOS支持的说明
Go 1.11开始压缩调试信息以减小二进制大小。 Delve本身支持此功能,但是LLDB和GDB都不支持macOS上的压缩调试信息。如果您使用的是LLDB或GDB,则有两种解决方法:使用-ldflags = -compressedwarf = false
生成二进制文件,或使用[splitdwarf](godoc.org/golang.org/x/ tools / cmd / splitdwarf)(获取golang.org/x/tools/cmd/splitdwarf
)以将调试信息解压缩为现有二进制文件。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。