栈溢出是函数调用帧压栈导致空间耗尽的崩溃,无c++异常、try/catch无效;快速确认法:ulimit -s查限制,gdb bt看调用深度——上百层重复调用即递归失控,2–5层且访问大局部数组则单帧过大,多线程中报内存访问失败需查线程栈大小。

bt 输出几百层?先用 bt 20 截断看顶部关键帧
崩溃点往往藏在最顶上几层,bt 默认全打出来反而干扰判断。直接输 bt 20 只显示最近 20 层,够定位 #0 崩溃指令和前几个关键函数调用;若怀疑是深层递归,再补 bt -20 看底部(比如是否卡在 malloc 或某个模板展开里)。
注意:bt 20 不是“从第 20 层开始”,而是“最多显示 20 层”,从 #0 往下数;bt -20 才是从栈底往上取最后 20 层。
哪些帧可以立刻跳过?识别编译器/库的“噪声帧”
GDB 的 bt 常混入大量无关帧,比如:
-
__libc_start_main、_start、main以下全是标准启动链,除非你改了入口,否则不用细看 -
std::function、std::_Function_handler、boost::_bi::bind_t这类模板展开帧,通常只说明“这里用了回调”,重点应放在它调用的业务函数上 -
pthread_cond_wait、epoll_wait、nanosleep等阻塞调用,如果它们出现在#0,说明不是崩溃点,而是线程挂起状态——得换线程查(info threads+thread N)
想快速定位业务代码帧?用 bt | grep -E "(MyClass|handle|on_|process)"
终端里直接管道过滤比在 GDB 里翻屏快得多。把项目里典型的类名、回调前缀、处理函数名列出来,比如:
bt | grep -E "(UserManager|onConnect|handleRequest|processEvent)"
能立刻筛出你写的逻辑所在帧;如果没匹配到,说明崩溃发生在第三方库或底层(比如 libavcodec 内部解码失败),这时要结合 info proc mappings 看地址落在哪个 so 段。
注意:grep 之前别忘了 set pagination off,否则 GDB 会卡在 “--More--” 提示上。
frame 0 看起来像库函数?用 x/5i $rip 和 info registers 看真实上下文
有时候 bt 显示 #0 0x00007f... in ?? () 或指向一个模糊符号(如 __GI___pthread_mutex_lock),这不代表崩溃在这里——只是当前指令指针停在这儿。真正线索在寄存器和指令流里:
-
x/5i $rip查看崩溃那条指令及前后几条,确认是不是mov %rax,(%rdi)这类写操作 -
info registers看$rdi、$rsi、$rax是否为 0、0xdeadbeef、或明显超出 mmap 区域的地址 -
info proc mappings对照地址范围,判断该地址是否属于已卸载的模块或非法内存
栈帧本身可能已被破坏,但 CPU 寄存器和指令指针不会说谎——这是绕过“bt 不可信”陷阱最硬的抓手。











