应优先用行号断点(如break main.cpp:23)和全名断点(如break MyClass::MyClass),模板函数需带完整签名;开启-g -O0编译以保证调试信息准确;core dump后结合bt、info registers、watch及valgrind定位;x命令需匹配真实内存布局,多线程调试须set scheduler-locking on。

gdb里怎么设断点才不漏掉关键位置
断点设不对,程序跑飞了都不知道卡在哪。最常见的是在优化后的代码里用break main,结果跳过初始化直接进循环——因为main被内联或重排了。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 用
break <filename>:<line></line></filename>比函数名更稳,比如break main.cpp:23 - 构造函数、析构函数要写全名:
break MyClass::MyClass,别只写MyClass - 模板函数得带签名:
break std::vector<int>::push_back</int>,否则gdb可能找不到 - 如果用了
-O2编译,先加-g -O0重新编译,不然行号和变量都对不上
core dump后怎么定位野指针或use-after-free
core文件本身不报错,但gdb ./a.out core进去后,bt常显示在malloc或operator delete里,这不是问题根源,是崩溃的“现场”,不是“案发地”。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 启动时加
set follow-fork-mode child,避免子进程崩溃没被捕获 - 用
info registers看rip和rsp附近有没有明显非法地址(比如0xdeadbeef或0x0) -
watch *(int*)0x7f8a12345678可以监听某个地址的读写,但仅限当前映射页;更靠谱的是运行前加valgrind --tool=memcheck辅助定位 - 如果怀疑是
std::shared_ptr误释放,用print *ptr.get()前先确认ptr.use_count()是否为0
想看某块内存内容,但x命令总输出看不懂
x不是“打印变量”,它是按原始字节解释内存,类型错了就全是乱码。比如把std::string对象当char*去x/10c,看到的只是内部指针字段,不是字符串内容。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 查堆上对象:先
info proc mappings确认地址是否在[heap]范围内,再x/4gx 0x7f8a12345678看8字节一组的原始值 - 查
std::vector数据:用print vec._M_impl._M_start@vec.size()(GCC libstdc++布局),而不是瞎x - 查虚表:用
x/5a *(void**)obj看前几个指针,第一个通常是vtable地址,再x/10a *(void**)0x7f8a...看虚函数地址列表 - 别依赖
x/10i $pc反汇编整个函数——用disassemble更准,它会识别指令边界
多线程下step总跳到别的线程,怎么锁死当前线程
默认step或next会切线程,尤其在std::mutex::lock()这种系统调用里,一跟就进内核线程调度逻辑,完全脱离你的代码上下文。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 进调试前先
set scheduler-locking on,之后所有单步、继续都只在当前线程内执行 - 想临时放开?用
set scheduler-locking off,但立刻thread apply all bt确认其他线程状态 - 查线程私有变量(如
thread_local static int x),必须先thread <n></n>切换过去,再print x,不能跨线程访问 - 注意
info threads显示的LWP ID和/proc/<pid>/task/</pid>下的目录名一致,可用来交叉验证是否真挂起
真正难的不是命令怎么敲,而是得清楚你怀疑的是哪一层的问题:是源码逻辑跳转异常?还是对象生命周期管理出错?还是多线程同步条件没满足?选错切入点,gdb再熟也白搭。










