聊聊程序常用调试有哪些?

程序开发,很大一部分的时间是用于调试,调试也是一门值得了解的学科,我这总结一般调试手段:

  1. 加日志
  2. 加断言
  3. 代码调试
  4. 调试core文件

加日志

这个就无需赘言了,你怀疑哪个地方,或者在出现问题的时候,需要知道哪个地方有问题,那么日志肯定是少不了的,而且这个也是最基本的,适用于所有语言。

但是经验来看,加日志属于事后,或者是预判,不是很灵活,因为总有你没想到的地方,所以我们发现,做程序开发,在排查线上问题的时候,总会抱怨其他程序员没有加日志。关键还是在于计划赶不上变化。

日志是必须的,但是只靠日志,在某些场景还是没法解决问题的:

  1. 你不知道哪个地方出了问题,你只能在怀疑的地方又加日志
  2. 每次加日志,你肯定得改代码,如果是编译型语言你还得重新打包,慢
  3. 加了日志之后,发现打印出的信息还是太少,返回去又搞一遍,返工

加断言

这个在 c 语言开发里经常看见,通常是你认为绝对的一段代码逻辑,直接断言,或者在排查问题的时候,怀疑某一个地方,那么加一个断言,这个本质逻辑就是:如果代码走到我怀疑的地方,那么就证明了我某些推论,断言之后,还可以留下内存 core 文件,以便调试。

调试core文件

这个是c/c++程序比较常见的一种调试方式,c 程序一般线上都会开 core 开关,到跑到异常的时候,整个程序内存镜像 dump 出来,相当于保存了现场。这个有时候也是排查 c 程序运行唯一手段。

golang程序经常用这种方式,排查一些问题。golang 有两个调试工具:

  • gdb
  • dlv

gdb 能调试 golang 程序的,但是不好调试,有几个原因:

  • 关键在于golang的协程是用户态的执行单元,gdb 调试的是系统的执行题,进程,线程,所以根本很难调试到指定的协程。
  • 协程数太多,这个也是最尴尬的地方,生产环境的 golang 程序动不动就成千上万个 goroutine,你列都列不完。
  • gdb 对 golang 程序的数据结构理解不完善。打印变量经常打印不出来。

但是 gdb 有自己的独一无二的特点:

  1. 可以 gcore 文件,这个 dlv 就做不到,所以我们经常用 gdb 来 core 文件,用 dlv 来分析 core
  2. x 命令分析内存更透测

代码调试

代码调试无论那种语言,都是很重要的一个环节。要能够离线的对二进制或者在线的对进程进行调试,设置断点喽,打印一些程序变量喽,这些都是无侵入式的,不需要改代码即可。

  1. 比如 c/c++ 可以使用 gdb 进行单步调试,或者 attach 到已经在运行的进程里进行调试。
  2. python 可以使用 pdb 进行单步调试
  3. golang 可以 gdb 和 dlv 进行离线和在线调试

golang 调试

golang 调试有两个工具:

  1. gdb
  2. dlv

都支持的三种调试场景:

  1. 二进制文件
  2. 在线进程
  3. core 文件
gdb
# 调试二进制文件
gdb --args {二进制文件} {参数}

# 调试在线进程
gdb {二进制文件} -p {pid}

# 调试 core 文件
gdb {二进制文件} {core 文件}
dlv
# 调试二进制文件
dlv exec {二进制文件} -- {参数} 

# 调试在线进程
dlv attach {二进制文件} {pid}

# 调试 core 文件
dlv core {二进制文件} {core 文件}

python 调试

python的调试有两个手段:

  1. 侵入式
  2. 非侵入式

侵入式

#!/usr/bin/env python

def test_print():
    # 断点位置
    import pdb; pdb.set_trace()
    print("test print")

if __name__ == "__main__":
    test_print()

0b23a12ea8fb8c0096e913fd829a7dc1.png

非侵入式

python -m pdb test.py

5caa693128123a01459d2062e7acdaa0.png

后面抽个时间分享下 gdb,dlv怎么调试golang程序的,敬请期待。


坚持思考,方向比努力更重要。关注公众号:奇伢云存储,获取更多干货。 关注我公众号, 获取更多干货