必须先执行ulimit -c unlimited,因为这是core dump生效的开关,内核崩溃时若该值为0则直接跳过写入,后续所有配置无效;还需针对systemd服务配置limitcore=infinity和processcoredump=yes。

崩溃时没 core 文件,先开 ulimit -c unlimited
程序一崩就消失,连堆栈都看不到,大概率是系统禁了 core dump。Linux 默认 core 文件大小限制为 0,得手动放开:ulimit -c unlimited。这句必须在启动程序前执行,不是写进代码里就能生效的。如果用 systemd 管理服务,还得额外配 LimitCORE=infinity 和 ProcessCoreDump=yes,否则即使 ulimit 设了也没用。
有 core 文件,用 gdb ./a.out core 看 bt
拿到 core 后别急着看日志,直接进 GDB:gdb ./a.out core。进去了只输 bt(backtrace),它会打出函数调用链。重点不是最顶上那一行,而是往上翻几层——段错误常发生在空指针解引用、std::string::c_str() 崩了,但真正问题可能是上层某个对象早被析构了,只是这时才暴露。如果 bt 显示地址乱码或帧不全,说明编译没加 -g,或者 core 和二进制文件版本不匹配。
崩溃不复现?试试 ThreadSanitizer
加日志后 bug 消失,八成是竞态导致的“幽灵崩溃”。这时候靠 core 没用,得换检测工具:g++ -fsanitize=thread -g your_code.cpp 编译。TSan 会在运行时报告数据竞争,比如两个线程同时读写同一个 int counter,它会精确指出哪两行代码在争抢,并标出访问类型(read/write)和线程 ID。注意:TSan 会显著拖慢运行速度,不能长期开着跑生产环境,但定位竞态足够准。
Windows 下没 pdb 只有 map 文件,怎么查?
VC 编译生成的 .map 文件里存着符号和地址映射,但不能直接看出源码行号,得配合崩溃时的异常地址算偏移。比如崩溃提示 access violation at 0x0040102F,打开 your_app.map,搜 “Publics by Value”,找到离这个地址最近的函数起始地址(比如 0001:00401000),算出差值 0x2F,再在 map 文件里找该函数的行号段(需开启 /mapinfo:lines 编译选项),按偏移定位具体行。过程繁琐,但比盲猜强。
真正麻烦的不是找不到崩溃点,而是崩溃点只是表象——野指针可能在 10 行前就失效了,竞态可能藏在另一个线程的初始化逻辑里,栈溢出甚至不会留下完整调用栈。所以别只盯着报错那一行,得把 core、ASan、TSan、map 几种手段当组合拳用。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











