调试工具入门:GDB、pdb、IDE 调试器
调试是编程的基本功,说白了你写的代码不可能一次全对。我刚入行时也怵调试,总觉得打几个 log 凑合够了。后来被一个内存泄漏折腾了两天,才老老实实把 GDB 捡起来。下面咱们挨个聊。
1. GDB — C/C++ 的调试利器
GDB 是命令行工具,没有图形界面,但功能极强。我个人习惯记几个常用的:
gdb ./myprogram
(gdb) break main # 在 main 入口设断点
(gdb) run # 开始运行
(gdb) next # 步过(不进入函数)
(gdb) step # 步入(进入函数内部)
(gdb) print variable # 打印变量值
(gdb) backtrace # 看调用栈
(gdb) continue # 继续运行到下一个断点
(gdb) quit
嗯,这里要注意——编译时一定要加 -g 选项。我曾经在 Makefile 里漏写了 -g,结果 GDB 进去符号全是乱码,当时我还以为工具坏了……其实是自己挖的坑。
-g -O0 重新编译一份。
再看一个实际场景:data-race 排查。我习惯设 watchpoint(硬件断点)看某个变量何时被修改:
(gdb) watch myvar
(gdb) continue
一旦值变化,GDB 自动暂停,配合 backtrace 就能定位写它的函数。这个技巧我在一次多线程 bug 中立了大功。
2. pdb — Python 调试器
Python 自带 pdb,简单直接。两种启动方式:
# 方式一:运行时插入断点
import pdb; pdb.set_trace()
# 方式二:命令行启动
python -m pdb my_script.py
常用命令:
l— 列出上下文代码n— 执行下一行s— 步入函数c— 继续到下一个断点p— 打印表达式q— 退出
举个例子:
def divide(a, b):
import pdb; pdb.set_trace()
return a / b
result = divide(10, 0)
调试时输入 p a, b 就能看到两个参数的值,然后用 n 步进发现除零错误。我通常在测试环境这么用,但记得上线前要删掉 set_trace(),不然服务会挂住。
import pdb; pdb.set_trace() 麻烦?可以预先在代码里只写 breakpoint()。Python 3.7+ 内置了这个函数,行为等价于 pdb.set_trace(),还能通过环境变量 PYTHONBREAKPOINT 切换调试器。
3. IDE 调试器(VS Code、PyCharm)
图形化调试让入门变得更轻松。断点、变量监视、调用栈全在一个窗口里。我记着第一次用 PyCharm 的 Evaluate Expression 时,感觉就像打开了新世界。
VS Code 调试:
- 在行号左侧点击设置断点(红色圆点)
- 按
F5启动调试,选择对应的 launch 配置 - 调试侧栏可以看:变量、监视表达式、调用栈、断点列表
- 支持条件断点:右键断点,输入
x > 100只在 x 大于 100 时暂停 - 日志断点(logpoint):不暂停,直接打印信息到控制台
// .vscode/launch.json 示例
{
"version": "0.2.0",
"configurations": [
{
"name": "Python Debug",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
}
]
}
PyCharm 调试:
- 断点、单步操作和 VS Code 类似
- 特色:Evaluate Expression(Alt+F8),可以在运行中间任意执行 Python 表达式,改变量值
- 条件断点、异常断点(停在任何异常处)都很方便
- 调试多进程/多线程时,可以在调试工具窗口的「线程」标签页切换上下文
有一次我在 PyCharm 里调试一个并发爬虫,几百个线程同时改共享队列。用条件断点设 queue.qsize() > 500,一下抓住数据竞争的点。要是用 print 日志,估计得打印半栋楼那么高的日志。
| 工具 | 适用语言 | 启动方式 | 常用操作/命令 | 优缺点 |
|---|---|---|---|---|
| GDB | C/C++、Rust、Go | gdb program |
break, run, next, print, backtrace, watch | 轻量,无 GUI;适合嵌入式、服务器调试 |
| pdb | Python | python -m pdb script.py 或 breakpoint() |
l, n, s, p, c, q | 内建,零配置;但缺少变量树浏览 |
| VS Code | 多语言 | 按 F5 + launch.json | 断点/条件断点/日志断点、监视、调用栈 | 跨平台,生态好;远程调试配置较复杂 |
| PyCharm | Python 为主 | 点击绿色爬虫按钮 | Evaluate Expression、条件断点、框架树 | 功能最全,开箱即用;商业版收费 |
4. 调试流程与最佳实践
不管用什么工具,调试的套路是相通的。下面这张图概括了我在实际项目中总结的流程:
一般我按这个思路走:
- 复现错误 — 确定环境、输入和步骤。不能稳定复现的问题最难调。
- 缩小范围 — 用二分法或 log 点,锁定出错的函数或代码块。
- 设置断点 + 单步执行 — 观察每一步变量变化,和预期对比。
- 检查调用栈 — 尤其在看异常时,调用栈能告诉你错误是怎么一路传上来的。
- 定位问题后修代码,修完马上重新测试。不要修完一个就跑,经常一修引出新 bug。
嗯,记住这些,调试就不再是撞大运,而是一套可以重复执行的流程。动手试一次比看十遍文章管用,赶紧打开你的 IDE 或者终端练一把吧。