尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

gdb---内存调试

gdb---内存调试 实用操作流程要想进行gdb调试首先要在编译阶段添加-g然后对运行文件加上前缀gdb进入gdb调试页面输入run运行会自动显示哪行出现了问题帮助我们debug接下来要学习的数据结构涉及到大量的内存空间管理和指针编写程序时很容易发生内存上的错误这时候常用的调试工具就是gdbgun debugger常见内存问题1.内存泄漏分配的内存没有释放或者移动了指向其的指针导致丢失这块内存的地址。最终使得内存无法被回收程序若持续运行被调用会导致可用内存越来越少程序崩溃void leak() { int *p malloc(100); // 函数结束p 销毁但指向的 100 字节未释放永远泄漏 } void lost_pointer() { int *p malloc(sizeof(int)); p malloc(sizeof(int)); // 原先的 p 丢失第一个分配块泄漏 ...... free(p); }2.越界访问读写超过数组大小或者分配内存大小的内存区域void overflow() { int *arr malloc(5 * sizeof(int)); for (int i 0; i 5; i) { // i5 时越界写入 arr[i] i; } free(arr); }3.使用未初始化的数值void uninit() { int x; printf(%d\n, x); // 未初始化可能触发随机行为 int *p malloc(sizeof(int)); printf(%d\n, *p); // 动态内存内容也是随机值未 memset 或赋值 free(p); }4.修改写入已释放的内存内存被释放后指针依旧存有地址且地址是有效的此时这处内存可能被其他程序调用此时修改这处内存的值会引发错误int *p malloc(sizeof(int)); if (p NULL) //防御性编程 { printf(malloc fail); return -1; } *p 42; free(p); *p 99; // 非法写入5.对一块内存空间重复释放int *p malloc(10); free(p); free(p); // 未定义行为程序通常会直接崩溃6.栈溢出递归过深导致栈空间不足void deep_recursion(int n) { char big[1000000]; // 每次递归占用大量栈空间 if (n 0) return; deep_recursion(n-1); }7.野指针int *p; // 指向的地址是随机的 *p 10; // 可能破坏已有程序修改了其他程序正在使用的空间8.内存碎片内存中有很多小的不连续的内存块导致总和内存看似足够其实无法满足一些新的内存申请。内存管理一般以1024字节为一单位申请堆区空间时尽量申请其因数或者倍数就可以一定程度上避免该问题编译时添加后缀 -Wall可以警告你哪些地方有可能出现问题printf(%s:%s:%d\n__FILE__,__func__,__LINE__;这个函数可以插入到怀疑有问题的函数附近可以看到程序运行到哪个文件哪个函数第几行。gdb调试页面中的基础命令1.list -- 查看源代码方便插入断点与调试2.b 行号 --下断点3.r -- run --从头开始运行点到断点处会停到引发bug的那行也会停4.p 变量名 -- 查看当前的变量5.n -- next ---单步调试6.quit -- 退出7.continue c 继续执行直到下个断点run是从头开始运行8.info locals # 显示当前栈帧的局部变量break function_name //在函数入口设断点function_name函数名使用x命令可以查看详细内存的值格式x /[个数][格式][大小] 地址- 格式x(十六进制), d(十进制), s(字符串), i(指令)- 大小b(字节), h(半字2字节), w(字4字节), g(8字节)示例(gdb) p arr # 打印指针本身的值即堆地址 $1 (int *) 0x5555555592a0(gdb) x/5dw arr # 以十进制、字为单位查看该地址开始的5个字 0x5555555592a0: 1 2 3 4 5 (gdb) x/20bx arr # 以十六进制字节查看20个字节顺便能够清晰看到小端存储Tips配合断点使用| 命令 | 常用缩写 | 说明 || watch var | wa var | 监视变量变化wa 是 watch 唯一前缀 || watch *0x... | wa *0x... | 监视地址内容变化 || rwatch *addr | rw *addr | 读监视点rw 为 rwatch 缩写 || awatch *addr | aw *addr | 读写监视点aw 为 awatch 缩写 |读监视点意思是只要程序读取访问了某个变量或地址的值GDB 就会立刻暂停程序。普通的watch意思是写改变了就停awatch意思是读写都停
返回列表