程序栈
说到堆栈帧,你得先说说程序栈。
记忆功能程序堆栈区是支持操作,通常共享堆。
程序栈通常占领内存区域的下部,而堆用的是上部。
程序栈存放栈帧,栈帧有时候也称为活跃记录或活跃帧。栈帧存放函数參数和局部变量。堆存放动态内存。
调用函数时,函数的栈帧被推到栈上。栈向上长出一个栈帧。
当函数终止时,其栈帧从程序栈上弹出。
栈帧所使用的内存不会被清理,可是终于可能会被推到程序栈上的还有一个栈帧覆盖。
动态分配的内存来自堆。堆向下生长。随着内存的分配与释放。堆中会布满碎片。
虽然堆是向下生长的,可是这仅仅是大体方向,实际内存可能位于堆上的任何位置。
栈帧的组织
栈帧由以下几个元素组成:
返回地址:函数完毕后要返回的程序内部地址
局部数据存储:为局部变量分配的内存
參数存储:为函数參数分配的内存
栈指针和基指针:执行时系统用来管理栈的指针
栈指针通常指向栈顶部。基指针通常存在并指向栈帧内部的地址,比方返回地址,用来协调訪问栈帧内部的元素。
这两个指针都不是C指针,他们是执行时系统管理程序栈的地址。
以下这个函数给出实例:
float average(int *arr, int size){
int sum;
printf("arr: %p\n",&arr);
printf("size: %p\n",&size);
priintf("sum: %p\n",&sum); for(int i = 0;i < size;i ++){
sum +=arr[i];
} return (sum *1.0f) / size;
} //output
//arr: 0x500
//size: 0x504
//sum: 0x480
当中參数地址和局部变量之间的空档。保存的是执行时系统管理栈所需的其它栈帧元素。
系统在创建栈帧时,将參数以跟声明时相反的顺序推到栈上,最后推入局部变量。在这个样例中,size在arr之后被推入。通常,接下来会推入函数调用的返回地址。然后是局部变量。推入它们的顺序和在代码中的顺序相反!
从原理上说,本例中的栈向上生长。只是栈帧的參数和局部变量以及新栈帧被加入到了低内存地址。
栈的实际生长方向和实际相关。
for语句中的i没有包括在栈帧中。这是由于C语言中把块语句当成“微型”函数。
将栈帧推到程序栈上时,系统可能会耗尽内存,这样的情况叫做栈溢出,一般会导致程序非正常终止。要牢记住每个线程都有自己的程序栈,一个或多个线程访问存储器中的同一个对象可能会造成冲突。
版权声明:本文博客原创文章,博客,未经同意,不得转载。