900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 全局变量和静态变量以及内存堆栈的关系

全局变量和静态变量以及内存堆栈的关系

时间:2023-07-11 20:01:50

相关推荐

全局变量和静态变量以及内存堆栈的关系

在编写程序时,内存的控制是很重要的一部分。关于全局变量和局部变量,静态变量的关系如何?以及他们在内存在是存储于哪部分的?做个记录,以便往后查看。

1. 全局变量和静态变量

全局变量:又称外部变量,与之相对的是局部变量,是从变量的作用域上来考量的。全局变量定义与函数外面,作用于整个程序;而局部变量则是定义在函数里面,仅作用于函数内部,无法跨函数作用。全局变量为静态分配,即程序执行之前就进行内存分配,不再改变(内存不再改变);而局部变量则是动态分配,在程序执行的时候进行内存分配。

静态变量:是从变量的内存分配上来考量的,与之相对的是动态变量。静态变量如其名,采用静态分配方式的变量,表现在代码程层面就是用static 或 extern 关键字修饰的变量即为静态变量。静态变量分为static和extern,两者作用域不同,static修饰的只能作用于单个程序文件,而extern 则可以作用于整个程序(多文件)。

全局变量和静态全局变量:当程序只有一个文件构成时,两个没有什么区别;当多个文件存在时,static全局变量则使得该变量为源文件独享(只作用于单个文件),而 extern 全局变量则可以作用整个程序,包括其他源文件。

那么静态局部变量呢?静态局部变量作用域与局部变量一致,只不过生命周期不一样,内存存储地点也不一样。静态局部变量是程序执行之前静态分配内存,程序执行结束之后结束。

看到有人提到静态变量无法改变,这是错误的。静态变量只是内存分配为静态分配方式,内存不变,并不是说不可以改变,静态变量也是可以更改存储内容的。

2. 全局变量,静态变量在内存中存放位置

我们知道一个汇编程序分为:代码段,数据段,堆栈段(这里的堆栈就是指的栈,stack)。从内存上说,数据段又可分为:静态存储区,堆(heap)和BSS(Block Started by Symbol)区。

代码段:就是存放程序二进制代码区域

静态存储区(.data):用于存放已初始化的全局变量和静态变量

堆(heap):数据区,用于动态分配的存储。一般由程序员控制分配和释放,malloc 和 new 的数据存放于堆中

未初始化全局(静态)变量BSS:未初始化的全局变量和静态变量,全局变量和静态变量默认初始化为0

堆栈(stack):通常理解就是局部变量,函数调用等所需存储

为了了解全局变量和静态变量等内存存储位置,talk is cheap, show the code! 给出一个测试案例,然后用objdump 或者 readelf反汇编指令,进行查看该程序生成的对应汇编程序结构,获取各个变量的内存段分配。

// tets.c#include <stdio.h>static int var_global_static_a = 1; // 初始化静态全局变量static int var_global_static_b;// 未初始化静态全局变量int var_global_a = 1;// 初始化全局变量int var_global_b;// 未初始化全局变量int main(){static int var_static_a = 1; // 初始化静态局部变量static int var_static_b; // 未初始化静态局部变量int var_a = 1; // 初始化局部变量int var_b; // 未初始化局部变量return 0;}

结果如下图所示:

objdump -t test.o

执行结果可知:已初始化的全局变量和静态变量(无论全局还是局部)都是存放于.data 段,而未初始化的静态变量则是存放在.bss 段,未初始化的全局变量存放在 .comment,这个不知道是干嘛的,但其实也是应该是 .bss 类似。而局部变量则并未出现在这里,因为局部变量位于堆栈段,是需要程序执行时进行分配的,所以这个只进行了编译的obj文件中并没有这两个变量的内存分配。

如果全局变量初始化都为 0呢?结果如下所示,全部都变成了 .bss 段。其实0是全局变量和静态变量的默认初始化值,即如果没有主动初始化而直接使用,则是默认初始化为0 。所以当主动初始化为0时,还是当成没有初始化处理,存放于 .bss 段

3. 堆(heap)和堆栈段(stack)

堆和栈总是一起别人提起,所以这里也放在一起来讲。有个概念需要区分开的,就是堆栈指的就是内存的stack部分,而不是堆和栈,堆是heap。有时候定义数组,因为过大,直接定义成局部变量的话就会爆,但是用 malloc 或者将数组变为全局变量,就不会爆。我们知道这这分别对应着堆栈存储 和 数据段(堆 和 静态存储区),那么他们的大小分别是多少呢?

3.1 堆的大小和堆溢出

堆作为数据段的一部分,理论上除去堆栈大小,代码段大小和全局变量静态变量等部分,剩下的都可以作为堆的内存分配范围。所以堆的大小一般比较大,几乎接近计算机内存(+虚拟内存)大小。关于堆溢出,如果持续进行 malloc 而不释放的话,那么就会产生堆溢出,爆堆。

3.2 堆栈大小和栈溢出

关于堆栈的大小,Linux下有个指令可以查看,一般情况下为8-10M。当局部变量大小大于这个数值或者递归层数过多时,进行发生栈溢出。

ulimit -a# ulimit -s //可直接查看堆栈大小

这里显示栈大小8M,可以用程序测试一下,栈的大小到底是否是这么大。测试程序参考linux下栈空间大小(ulimit):

#include <stdio.h>#include <stdlib.h>void test(int i){char temp[1024*1024] = {0};printf("%s %d num = %d!\r\n", __FUNCTION__, __LINE__, ++i);test(i);}int main(void){test(0);return 0;}

测试结果确并未如我上面参考的那个博主的一样,他得出Linux下主线程栈大小比子线程多大概2M的样子,可是我的测试结果都是一样(至少在M级是一样),结果如下:

结果证实了此前查询得出的栈大小为8M 这个事实(因为还有参数传递,和局部变量,所以是肯定到达不了8的)。为了知道我计算机的实际栈大小,以及后续的证实,进行了手动二分来确定栈具体大小(有点傻。。)

理论上堆栈空间8M=8*1024*1024 = 2*1024*1024 = 2097152 个int

还有 .bss区大小的问题没有测试,未完待续,有时间再补充吧。。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。