相关文章推荐
有胆有识的鼠标垫  ·  (gdb) break ...·  3 月前    · 
霸气的伏特加  ·  docker-逃逸提权 - ...·  1 年前    · 
俊秀的牙膏  ·  Android ...·  1 年前    · 
彷徨的酱牛肉  ·  Maven Surefire ...·  1 年前    · 

栈的英文是stack,堆的英文是heap,很多人把stact翻译成堆栈,是不对的。

栈由栈帧组成 。当一个函数调用时,栈会为这个函数分配一个栈帧,用于存储函数的实参、局部变量、返回值,以及函数内调用函数时,当前函数的一些寄存器的相关信息(比如用于指向下一条指令的程序计数器)。 可以认为,一个栈帧存储一个函数。 当该函数调用结束后,栈帧会自动从栈上移去(这解释了局部变量的生存期问题)。

由于函数的嵌套,栈中可能有多个栈帧,此时, 最后分配的栈帧称为栈顶 ,如下图所示。栈指针寄存器用于存储栈顶的地址,以跟踪栈顶。

下面,我们使用GDB查看一个实例的栈信息。实例程序gdbtest.cpp如下:

#include <stdio.h>

int square(int a, int b){

int ret = a*a + b*b;

return ret;

int doCalc(int num1, int num2){

int ret = square(num1, num2);

return ret;

int main(){

int param1 = 1;

int param2 = 2;

int result = doCalc(param1,param2);

printf("result is%d\n",result);

编译:g++ -g  gdbtest.cpp

启动gdb:gdb  a.out。

由源文件可知,main函数里面嵌套doCalc函数,doCalc函数又嵌套square函数,因此,这三个函数在栈中的分配如上图所示。在square函数中设置断点,程序停在断点后,使用backtrace命令,即可看到栈内容,如下所示:

(gdb) backtrace

#0  square (a=1, b=2) atgdbtest.cpp:6

#1  0x00000000004005e6 in doCalc(num1=1, num2=2) at gdbtest.cpp:10

#2  0x0000000000400613 in main ()at gdbtest.cpp:17

每一行前面的序号,就是栈帧在栈中的序号,#0表示栈顶,#1表示下一个栈帧,以此类推。使用frame 1,可以选择1号栈帧,使用info locals可以当前栈帧的局部变量:

(gdb) backtrace

#0 square (a=1, b=2) at gdbtest.cpp:6

#1 0x00000000004005e6 in doCalc (num1=1, num2=2) at gdbtest.cpp:10

#2 0x0000000000400613 in main () at gdbtest.cpp:17

(gdb) frame 1

#1 0x00000000004005e6 in doCalc (num1=1, num2=2) at gdbtest.cpp:10

10       int ret = square(num1, num2);

(gdb) info locals

ret = 0

(gdb)

GDB 中为我们提供了查看 内存 的命令 x,它是 examine 命令的简写,使用 x 命令查看 内存 数据的格式有很多种,这里的 内存 数据可以是任意类型。命令的详细介绍如下。 参数 f 的可选值: x 按十六进制格式显示变量。 d 按十进制格式显示变量。 u 按十六进制格式显示无符号整型。 o 按八进制格式显示变量。 t 按二进制格式显示变量。 a 按十六进制格式显示变量。 c 按字符格式显示变量。 f 按浮点数格式显示变量。 参数 u 的可选值: b 表示单字节 h 表示双字节 w 表示四字节 g 表示八 二、 内存 泄漏检查和调试 2.1 内存 泄漏 内存 泄漏是指程序中已动态分配的堆 内存 由于某种原因程序未释放或无法释放,由于一个进程的堆空间始终是有限的,32位的程序最多可以使用的 内存 不会超过2GB,如果代码中存在 内存 泄漏,短时间内程序不会崩溃,但是长时间运行直到没有 内存 可分配时,程序会崩溃。 调用堆 是当前函数之前的所有已调用函数的列表,每个函数及其变量都被分配了一个” 帧”,使用 GDB 查看函数调用堆 可清晰地看到各个函数的调用顺序以及各函数的输入形参值,是分析程序的执行流程和输入依赖的重要手段。 为了便于讲解,本文基于下述通过递归算法计算斐波拉契数列的简单 demo 进行举例说明。`#include<stdio.h> #include<stdlib.h> int fibonacci(int n) if (n == 1 || n == 2) return.. 内存 断点可以帮助我们查找一些 内存 的问题, 而 内存 问题往往都是比较棘手的问题。所以掌握 GDB 内存 调试还是很有用的,下来我们就开始 GDB 内存 断点之旅。 我们通过一个程序来学些这个方法: 注意涉及的指令就是rwatch、watch和awatch,分别表示读、写、读写。需要注意的是我用的这个版本直接用地址是断不下来的,必须用*(char*)之类来进行强制类型转换,不知道其它 当程序进行函数调用时,这些调用信息(比如在哪里调用等)称为 帧。每一个 帧的内容还包括调用函数的参数、局部变量等。所有 帧组成的信息称为调用 (或者调用堆 )。当程序刚开始运行时,只有一个 帧,即主函数 。每调用一个函数,就产生一个新的 帧;当函数调用结束时(即从函数返回后),该函数的调用随之结束,该 帧也结束。如果该函数是一个递归函数,则调用该函数会产生多个 帧。查看 回溯信息的命令是 。执行该 回溯命令后,会显示程序执行到什么位置、包含哪些帧等信息。每一帧都有一个编号,从 0 开始。0 表示当前正在执