调试排查工具介绍(gdb、strace、Valgrind等)

1.GDB用户态调试 /KGDB内核级调试

使用GDB调试之前,需要用-g选项编译程序,这样可执行文件中才会包含符号表(变量名、函数名、行号等信息)g++ -g -o myprogram myprogram.cpp

bash 复制代码
 #步骤1:启动GDB并设置断点,(delete是删断点)
gdb ./test
(gdb) break main             # 在main函数入口打断点
(gdb) break 25               # 在源文件第25行打断点
(gdb) break func1 if x==100  # 条件断点:x等于100时才触发
(gdb) info breakpoints       # 查看所有断点
# 步骤2:运行程序
(gdb) run                    # 开始运行,直到遇到断点
(gdb) run arg1 arg2          # 带命令行参数运行
(gdb) run < input.txt        # 重定向标准输入
# 步骤3:当程序停在断点时,单步执行与继续
(gdb) next        # n,单步执行,不进入函数内部
(gdb) step        # s,单步执行,会进入函数内部
(gdb) continue    # c,继续运行,直到下一个断点或程序结束
(gdb) finish      # 执行完当前函数并返回(跳出函数)
(gdb) until 30    # 运行到第30行(用于跳出循环)
# 步骤4:查看状态
(gdb) print var           # 打印变量var的值
(gdb) display var         # 每次暂停时自动打印var的值
(gdb) info locals         # 查看当前函数的所有局部变量
(gdb) info registers      # 查看寄存器内容
(gdb) backtrace           # bt,查看函数调用栈(崩溃时最常用)
(gdb) list                # 显示当前执行的源代码
(gdb) disas               # 显示汇编代码
# 步骤5:修改变量(调试时临时改变行为)
(gdb) set var x=100       # 将变量x的值改为100
(gdb) call func2()        # 手动调用函数func2

++举例:++

段错误 (core dumped) : SIGSEGV 信号,错误码编号为 11。是由于程序尝试访问不存在的内存区域引发的。

常见原因如下:

  • 访问未初始化的指针(空指针解引用),ptr 未指向合法内存(如未通过new 分配内存)。

  • 数组越界访问

  • 释放后使用内存

  • 栈溢出。递归过深或局部变量占用过多栈空间。

如何定位和解决?

运行 GDB执行程序,查看堆栈信息:(gdb) bt(Backtrace)定位错误位置。

利用gdb调试器跟踪调用栈

使用gdb,在程序崩溃时查看调用栈(bt命令),定位最后执行的函数,检查该函数中是否有异常内存操作。若栈溢出,调用栈会显示递归层数过深的函数;若堆溢出,可能指向new/malloc的异常调用。

Core Dump文件是程序崩溃时的内存快照,包含虚拟内存布局、寄存器状态、调用栈等信息。

具体实现:

  • 解析 Core Dump 中的 "程序头" 获取内存段信息(代码段、数据段、堆、栈的地址范围);

  • 从栈内存中提取调用栈(函数返回地址),映射到源代码的行号;

  • 查看堆内存中的对象状态(如通过print查看指针指向的内存内容),判断是否有异常分配(如超大对象)。

2. strace /ftrace / ltrace / ptrace/bpftrace 等,或使用trace-cmd工具

  • ptrace:Linux 的系统调用接口(API),供调试/跟踪进程使用。

  • strace:基于 ptrace,跟踪进程执行时的 系统调用 和 接收到的信号。是排查线上故障(如文件打不开、权限错误、网络连接失败等)的首选工具。

  • ltrace:跟踪用户态库函数(动态链接的函数调用),通常也基于 ptrace。

  • ftrace:内核内建的跟踪框架,跟踪内核函数、上下文切换、IRQ、调度等,需在内核/tracefs 中使用(通常需 root)。

bash 复制代码
# -c 打印执行uptime时系统系统调用的时间、次数、出错次数和syscall
strace -c uptime
# -f 跟踪主进程及其所有子进程(对 shell 脚本、多进程程序很重要)
strace -f ./my_script.sh
# 显示 ls 命令执行过程中所有的系统调用(如 openat, read, write, close 等)
strace ls /tmp
# 把 strace 输出写入 debug.log,避免干扰终端
strace -o debug.log nginx -t
# 跟踪 PID 为 1234 的进程(需有权限),常用于诊断卡住的服务
strace -p 1234
# 只跟踪特定类型的系统调用,如open、read、write、network等
strace -e trace=open,read,write curl https://example.com

++strace 使用实践++:定位一次系统无法解析域名故障。

无法访问外网域名,提示Name or service not know。且已检查系统DNS配置文件/etc/resolv.conf正确,排除DNS解析失败。域名解析通常跟系统读取文件相关,因此只查看open file的过程。

strace -e strace=open ping www.baidu.com

如上图所示在系统调用过程中出现/usr/lib64/libnss_dns.so.2文件缺失,则问题根因已确定为libnss_dns.so.2系统库文件缺失。libnss_dns.so.2文件由glibc-devel包产生,因此重新安装该包即可。

3.Valgrind - 内存泄漏检测 (该释放的资源没有及时释放)

内存泄漏原因:

1.new/delete,new\[\]/delete\[\] 没有配对使用,忘记释放动态分配的内存;

2.异常安全漏洞:异常改变了正常的执行流程,导致释放代码被跳过;

3.当多个部分共享同一内存时,释放责任不明确;

4.使用STL容器时存储了指针,清空容器时,指针指向的资源其实并没有释放,造成内存泄漏;

5.智能指针循环引用问题

**方法:**使用完内存或资源后立即释放;使用智能指针自动管理内存生命周期;RAII 类封装资源。

内存池能显著降低内存泄露的风险,一次性从系统申请一大块内存;后续的小对象分配不再调用 new/malloc,而是从池中切分;当整个池不再需要时,一次性释放整块内存,无需逐个 delete。

valgrind

  • 安装完valgrind,编译程序时一定加上-g! gcc -g -o leak leak.c

  • 运行Valgrind检测,valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./leak

--tool=memcheck:使用内存检查工具(默认工具)

--leak-check=full:详细显示内存泄漏信息

--show-leak-kinds=all:显示所有类型的泄漏

--track-origins=yes 追踪未初始化值的来源

--log-file=valgrind.log 将输出保存到文件

--num-callers=20 显示20层调用栈

  • 分析Valgrind输出结果,解读关键信息,比如:

definitely lost: 100 bytes:明确的内存泄漏,100字节

by 0x10916D: main (leak.c:6):泄漏发生在 leak.c 文件的第6行(就是 malloc(100) 那行)

1 allocs, 0 frees:分配了1次,释放了0次

ASan

另一个方法是ASan(AddressSanitizer)生成报告,但不一定100%罗列出来问题。

优点是比 Valgrind 快很多,但泄漏检测不如 Valgrind 精确。需额外开启内存泄漏检测:

gcc -fsanitize=address -fno-omit-frame-pointer -g -o leak leak.c

相关推荐
卷无止境2 小时前
C++ 存储类说明符(Storage Class Specifier)大横评
c++·后端
卷无止境2 小时前
C++ 编程的一大坑:非常量全局变量是"万恶之源"
c++·后端
C语言小火车2 小时前
C++ 快速排序(Quick Sort)深度精讲:分治思想、Lomuto 分区法及三数取中优化,面试手撕必会
c语言·开发语言·c++·面试·排序算法·快速排序
sycmancia2 小时前
Qt——多线程间的互斥
开发语言·qt
一知半解仙2 小时前
2026年彻底免费的辅助编程Agent大模型汇总
开发语言·人工智能·开源
lzqrzpt2 小时前
LED驱动电源选型标准与工程应用技术要点解析
python·单片机·嵌入式硬件·物联网
Mr-Wanter2 小时前
wsl2 jdk管理工具之sdkman
java·开发语言·sdkman
2502_921286072 小时前
【企业网络管理】DHCP 与 SAMBA:从协议原理到企业级实战配置全解析
开发语言·php
矮小的方盒2 小时前
关于大型网站技术演进的思考(一)--存储的瓶颈(1)
开发语言