核心思路是先确认是否真段错误,再判断地址非法或合法但映射异常;优先查dmesg和系统日志排除oom killer等系统级干扰,确保core dump可用,用gdb分析调用栈与内存映射,警惕物理页回收导致的“地址合法却崩溃”。

遇到服务因 SIGSEGV 崩溃,核心思路是:先确认是不是真“段错误”,再判断是地址非法,还是地址合法但内容/映射异常。别一上来就翻业务代码——很多问题根本不在业务逻辑里。
看日志和信号来源
先查系统级线索:
- 运行 dmesg -T | grep -i "seg\|kill\|oom",重点看崩溃时间附近有没有内存压力、OOM killer 日志或页表异常提示
- 检查 /var/log/messages 或 journalctl -u your-service --since "2 hours ago",确认是否是内核主动 kill(比如 OOM-killer 发送 SIGKILL,但日志误标为 SIGSEGV)
- 注意区分:SIGSEGV 是进程自己出错;SIGKILL 是别人干的。两者处理方式完全不同
确保 core dump 能生成并可用
没有 core 文件,等于没现场:
- 执行 ulimit -c,必须不是 0;临时设为 ulimit -c unlimited
- 检查 /proc/sys/kernel/core_pattern,建议设成 /tmp/core.%e.%p.%t,带时间戳不易覆盖
- 确认程序启动环境(如 systemd service)也继承了 ulimit,否则后台服务常不生效;可在 service 文件中加 LimitCORE=infinity
- 验证权限:目标路径可写、磁盘有空间、SELinux/AppArmor 没拦截
用 gdb 分析 core 文件
拿到 core 后,快速定位关键信息:
- 用 gdb ./your-binary core.xxx 加载,输入 bt full 看完整调用栈和局部变量
- 关注崩溃点的地址:如果是指针解引用(如 mov %rax, (%rdx)),检查 $rdx 是否为 0、极小值或已释放地址
- 用 info proc mappings 查看该地址是否落在合法内存区域(heap、stack、mapped file);若落在堆区但 malloc_usable_size 返回 0,可能是 use-after-free
- 若栈帧混乱或 bt 显示 ??,说明符号缺失或栈被破坏,需确认编译时加了 -g,且未 strip
排除物理页映射失效这类隐性问题
当崩溃地址在堆内存范围内、几秒前还能正常读写,大概率是物理页被回收:
- 查 /proc/meminfo 中 MemFree 和 SwapCached,压测时若 MemFree 极低、SwapCached 飙升,就是内存紧张征兆
- 确认是否用了大块匿名内存池(如 mmap + PROT_READ|PROT_WRITE),且没做 mlock() 或 madvise(MADV_WILLNEED)
- 复现方法:用 madvise(MADV_DONTNEED) 主动触发页回收,观察是否稳定复现 SIGSEGV











