进程的​​内存​​布局如下图所示,栈是其中一块向下(低地址处)增长的内存。

GDB观察栈的内存布局_嵌套

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

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

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

GDB观察栈的内存布局_java_02

下面,我们使用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)



</article>


进程的​​内存​​布局如下图所示,栈是其中一块向下(低地址处)增长的内存。

GDB观察栈的内存布局_嵌套

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

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

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

GDB观察栈的内存布局_java_02

下面,我们使用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)