全局变量和静态变量以及内存堆栈的关系
在编写程序时,内存的控制是很重要的一部分。关于全局变量和局部变量,静态变量的关系如何?以及他们在内存在是存储于哪部分的?做个记录,以便往后查看。
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文件中并没有这两个变量的内存分配。
.data | var_global_static_a | 初始化全局变量和静态变量 |
var_static_a | ||
var_global_a | ||
.bss | var_global_static_b | 未初始化全局变量和静态变量 |
var_static_b | ||
var_global_b (显示是 .COM) | ||
未分配 | var_a | 局部变量 |
var_b |
如果全局变量初始化都为 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区大小的问题没有测试,未完待续,有时间再补充吧。。
全局变量和静态变量以及内存堆栈的关系相关推荐
- 深入理解C语言系列之内存和地址的故事(虚拟内存分区、全局变量与静态变量、外部函数内部函数、选择性编译)
文章目录 一.内存的分区 二.虚拟内存分区 三.变量作用域与静态变量 四.外部函数与内部函数 五.include与define选择性编译 一.内存的分区 1.内存分为:物理内存和虚拟内存. 物理内存︰ ...
- python中静态变量的作用_小白必读文章之全局变量与静态变量
全局变量与静态变量 static 声明的变量在C语言中有两方面的特征: 1.变量被放在程序的全局存储区中,这样在下一次调用的时候还可以保持原来的赋值.这一点是它与堆栈变量和堆变量的区别. 2.变量用s ...
- 全局变量、局部变量、静态全局变量、静态局部变量在内存里的区别(转)
转:http://blog.163.com/zhangkai-@126/blog/static/312636552011101510416242/ 一.程序的内存分配 一个由C/C++编译的程序占用的 ...
- java 静态全局变量_静态变量static和全局变量global
静态变量static , 全局变量global 静态变量 在java也叫类变量从名字可以看出它是属于某个类的而不是类的实例.它的关键字是static存储在静态存储区,当程序执行,类的代码被加载到内存, ...
- c++全局变量与静态变量
概述: 全局变量和和由static修饰的静态变量都被储存在全局数据区.全局数据区的内存在程序运行时会被全部置'0'.这不同于局部变量,局部变量在栈上分配内存,但此块内存一般不为零,且编译器不会在局部变 ...
- 【C++】局部变量、全局变量、静态变量与动态对象的性质
[fishing-pan:https://blog.csdn.net/u013921430转载请注明出处] 概述 局部变量 在一个函数内部定义的变量(包括函数形参)是局部变量. 全局变量 在函数外定义 ...
- 详解全局变量,全局变量与静态变量的区别
特点: ① 作用域:全局可见. 全局变量(外部变量)是在函数外部定义的,它的作用域为从变量的定义处开始,到本程序文件的末尾. 注:通常把超出一个函数的作用域称为全局作用域, ...
- 局部变量、全局变量、静态变量
局部变量 定义:局部变量指在程序中只在特定过程或函数中可以访问的变量.换言之,在一个函数内部定义的变量是内部变量,它只在本函数范围内有效,也就是说只有在本函数内才能使用它们,在此函数以外时不能使用这些 ...
- react-native全局变量和静态变量使用
react-native 多个类引入变量,可以使用下面三个方式 静态变量 全局变量的使用: 1 导入文件方式 2 全局变量方式 实现类 Test.js import {Button, Text, Vi ...
最新文章
- iceberg问题小结
- Mycat实现读写分离
- VIM 命令使用大全
- 几个值得收藏的国外有关Vue.js网站
- PostgreSQL 8.3 以上的中文全文索引使用介绍
- 浅析无字符数字构造webshell
- linux文件的打包与下载总结,linux下文件的打包和压缩
- Nginx源码安装,配置开机自启
- 在mac 上安装 mpkg
- 相对湿度与绝对湿度转换表包含负温度
- chrome主页被修改(Google Chrome主页被hao123劫持解决办法)
- 新教育杂志新教育杂志社新教育编辑部2023年第6期目录
- 概率论基础 —— 3.离散型、连续型概率模型,及其概率密度与概率分布函数
- Android热更新,android组件化通信
- python -- 字符串练习题
- 数据包结构(IVI,NID,CTL,TTL,SEQ,SRC,DST,TransPDU,NetMIC)
- Qt文件QFile 和文件夹QDir
- @WebFilter不拦截 action
- MTK平台Modem(2G、3G、4G)配置之编译环境搭建
- 腾讯云服务器配置https 部署安装ssl证书
热门文章
- YOLO系列目标检测算法详解
- 《Tomcat内核设计剖析》勘误表
- 三个变量存在一个协整方程_计量经济学31个简答参考答案
- 数据结构(十六)——左高树(含合并过程详细图解)
- Acwing:COW(DP+状态机 Python)
- 谷歌卫星地图下载器bigemap的优势
- [收藏]《观察与思考》:相信中国,寻找下一个比尔·盖茨
- 一大早,是什么让技术群发出强人锁男、男上加男、勉为骑男?
- 运维(39) 通过KubeSphere部署SpringBoot到K8S案例 DevOps
- 【人工智能】八数码问题:广度搜索、深度搜索