你好,我是小X。

曹大最近开 Go 课程了,小X 正在和曹大学 Go。

这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go。

今天介绍几个常用的查看 Go 汇编代码、调试 Go 程序的命令和工具,既可以在平时和同事、网友抬杠时使用,还能在关键时刻打他们的脸。

比如,有同事说这段代码:

package maintype Student struct {Class int
}func main() {var a = &Student{1}println(a)
}

的执行效率要高于下面这段代码:

package maintype Student struct {Class int
}func main() {var a = Student{1}var b = &aprintln(b)
}

并且给你讲了一通道理,你好像没法辩赢他。怎么办?

直接用一行命令生成汇编代码,马上可以戳穿他,打他的脸。

go tool 生成汇编

其实很简单,有两个命令可以做到:

go tool compile -S main.go

和:

go build main.go && go tool objdump ./main

前者是编译,即将源代码编译成 .o 目标文件,并输出汇编代码。

后者是反汇编,即从可执行文件反编译成汇编,所以要先用 go build 命令编译出可执行文件。

二者不尽相同,但都能看到前面两个示例代码对应的汇编代码是一致的。同事的“谣言”不攻自破,脸都被你打疼了。

找到 runtime 源码

Go 是一门有 runtime 的语言,什么是 runtime?其实就是一段辅助程序,用户没有写的代码,runtime 替我们写了,比如 Go 调度器的代码。

我们只需要知道用 go 关键字创建 goroutine,就可以疯狂堆业务了。至于 goroutine 是怎么被调度的,根本不需要关心,这些是 runtime 调度器的工作。

那我们自己写的代码如何和 runtime 里的代码对应起来呢?

前面介绍的方法就可以做到,只需要加一个 grep 就可以。

例如,我想知道 go 关键字对应 runtime 里的哪个函数,于是写了一段测试代码:

package mainfunc main() {go func() {println(1+2)}()
}

因为 go func(){}() 那一行代码在第 4 行,所以,grep 的时候加一个条件:

go tool compile -S main.go | grep "main.go:4"// 或go build main.go && go tool objdump ./main | grep "main.go:4"

go func

马上就能看到 go func(){}() 对应 newproc() 函数,这时再深入研究下 newproc() 函数就大概知道 goroutine 是如何被创建的。

用 dlv 调试

那有同学问了,有没有其他可以调试 Go、以及和 Go 程序互动的方法呢?其实是有的!这就是我们要介绍的 dlv 调试工具,目前它对调试 Go 程序的支持是最好的。

之前没我怎么研究它,只会一些非常简单的命令,这次学会了几个进阶的指令,威力挺大,也进一步加深了对 Go 的理解。

下面我们带着一个任务来讲解 dlv 如何使用。

我们知道,向一个 nil 的 slice append 元素,不会有任何问题。但是向一个 nil 的 map 插入新元素,马上就会报 panic。这是为什么呢?又是在哪 panic 呢?

首先写出让 map 产生 panic 的示例程序:

package mainfunc main() {var m map[int]intm[1] = 1
}

接着用 go build 命令编译生成可执行文件:

go build a.go

然后,使用 dlv 进入调试状态:

dlv exec ./a

使用 b 这个命令打断点,有三种方法:

  1. b + 地址

  2. b + 代码行数

  3. b + 函数名

我们要在对 map 赋值的地方加个断点。先找到代码位置:

cat -n a.go

看到:

hello.go

赋值的地方在第 5 行,加断点:

(dlv) b a.go:5
Breakpoint 1 set at 0x45e55d for main.main() ./a.go:5

执行 c 命令,直接运行到断点处:

运行到断点处

执行 disass 命令,可以看到汇编指令:

disass

这时使用 si 命令,执行单条指令,多次执行 si,就会执行到 map 赋值函数 mapassign_fast64

mapassign_fast64

这时再用单步命令 s,就会进入判断 h 的值为 nil 的分支,然后执行 panic 函数:

panic

至此,向 nil 的 map 赋值时,产生 panic 的代码就被我们找到了。接着,按图索骥找到对应 runtime 源码的位置,就可以进一步探索了。

除此之外,我们还可以使用 bt 命令看到调用栈:

调用栈

使用 frame 1 命令可以跳转到相应位置。这里 1 对应图中的 a.go:5,也就是我们前面打断点的地方,是不是非常酷炫。

上面这张图里我们也能清楚地看到,用户 goroutine 其实是被 goexit 函数一路调用过来的。当用户 goroutine 执行完毕后,就会回到 goexit 函数做一些收尾工作。当然,这是题外话了。

另外,用 dlv 也能干第二部分“找到 runtime 源码”活。

总结

今天系统地讲了几招通过命令和工具查看用户代码对应的 runtime 源码或者汇编代码的方法,非常实用。最后再汇总一下:

  1. go tool compile

  2. go tool objdump

  3. dlv

使用这些命令和工具,可以让你在看 Go 源码的过程中事半功倍。

好了,这就是今天全部的内容了~ 我是小X,我们下期再见~


欢迎关注曹大的 TechPaper 以及码农桃花源~

曹大带我学 Go(3)—— 如何用汇编打同事的脸相关推荐

  1. 『曹大带我学 Go 』系列文章汇总

    你好,我是小 X. 之前写了 11 篇跟着曹大学 Go 的文章,今天来汇总一下. 曹大的功力深厚,但能学到多少全看自己.第一期 Go 训练营也早就结束了,但学习还得继续.后面我也会继续发布这个系列,希 ...

  2. 曹大带我学 Go(8)—— 一个打点引发的事故

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 最近线上事故频发,搞得焦头烂额,但是能用上跟曹 ...

  3. 曹大带我学 Go(6)—— 技术之外

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 有学员私下和我说,这个课程挺打击他的自信心.我 ...

  4. 曹大带我学 Go(2)—— 迷惑的 goroutine 执行顺序

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 上一篇文章我们讲了 Go 调度的本质是一个生产 ...

  5. 曹大带我学 Go(12)—— 面向火焰图编程

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 现实中听过各种面向 XX 编程,什么面向过程编 ...

  6. 曹大带我学 Go(11)—— 从 map 的 extra 字段谈起

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 熟悉 map 结构体的读者应该知道,hmap ...

  7. 曹大带我学 Go(10)—— 如何给 Go 提性能优化的 pr

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 之前 qcrao 写了一篇<成为 Go ...

  8. 曹大带我学 Go(9)—— 开始积累自己的工具库

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 不知道你有没有这样的经验:看了很多计算机相关的 ...

  9. 曹大带我学 Go(7)—— 如何优雅地指定配置项

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 最近一个年久失修的库导致了线上事故,不得不去做 ...

  10. 曹大带我学 Go(5)—— 哪里来的 goexit

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 在学员群里,有同学在用 dlv 调试时看到了令 ...

最新文章

  1. Ubuntu更新时遇到/boot空间不足
  2. 【翻译】【linux设备驱动】linux地址类型
  3. mysql olap 工具_OLAP分析工具之Presto
  4. 全球及中国皮裤行业消费需求及未来产销前景预测报告2022-2027年
  5. 使用CNN进行情感分类
  6. “我,程序员,33岁,距离退休,只剩2年了!”
  7. 001mongodb数据库介绍002mongodb的增删改查003数据导入导出
  8. 软件工作相关考试001---PMP等各种考试
  9. mysql做时间判断_mysql关于时间函数的判断
  10. 猿大师播放器网页播放海康威视RTSP流闪退,用新版VLC播放器播放也闪退,但是用某个老版本VLC播放器却没问题,该怎么办?
  11. ERPS(Ethernet Ring Protection Switching):以太网多环保护技术
  12. 交换机芯片技术知多少
  13. PDF文件转MOBI怎么转?在线操作轻松完成
  14. 八种抽样技术的科学指南
  15. js之Symbol类型
  16. HTML+CSS+JS雷霆战机
  17. 【嵌入式软件开发】之面试常识(一)
  18. 影集制作php源码_最新仿720全景在线制作云平台网站PHP源码
  19. C++ function关键字
  20. linux环境安装部署RF+Jenkins+Git(非完整版)

热门文章

  1. 高效办公!Python 批量生成PDF文档
  2. 10_放置街灯(Placing Lampposts,UVa 10859)
  3. 【必读推荐】程序员的职业素养
  4. 我是个28岁的IT,我现在慌得一比
  5. 关于 网易云音乐 我喜欢的音乐 排序无法改为添加时间 排序无法还原 的问题
  6. pytorch锁死在dataloader(训练时卡死)
  7. python 正态分布图_用python制作正态分布图
  8. 学计算机编程我有什么好处,学习计算机编程对我们都有什么好处?
  9. 搜索引擎的目标是什么?
  10. 用python处理excel数据做函数_如何使用python通过函数式编程完成excel中的数据处理及分析工作...