const,static,extern存储区域+创建/销毁时间+作用域
文章结构如下:
- 进程的内存空间布局;
- 变量的链接属性;
- 变量的作用域与存储类型;
- const,static,entern存储区域,创建/消亡时间总结。
1.进程的内存空间分布
可执行文件加载进内存后形成的进程在内存中的结构,从不同数据上看到了两种:
第一种自下向上为:代码区、数据区+BSS区、堆区、栈区;
第二种自下向上为:代码区、常量区、静态/全局区、堆区、栈区;
个人认为这两种区域划分实际表示的结果都是一样的,第一种数据区存放了常量、已初始化的全局/静态变量;BSS区存放未初始化的全局/静态变量。所以,两种划分方法存储的结果是一致的。
进程在内存中的结构如下:
2.变量的链接属性
变量的链接属性决定如何处理在不同文件中出现的变量。有点难以理解,简单介绍一下。
从程序到可执行文件大概经历了:预处理、编译、汇编、链接四个阶段。其中链接阶段负责链接多个文件以及数据库。
变量的链接属性就决定了不同文件中的同名变量是不是同一个变量。
链接属性有三种:external(是同一变量)、internal(不是同一个变量)、none(无)。
一般来说,缺省代表外部。
三个链接属性与extern、static有什么关系呢?
通过extern、static在声明时可以修改变量的链接属性(extern→external,static→internal)具体规则如下:
- 在代码块外部缺省即代表externel修饰;
- static只对缺省的external有效(static extern还是extern);
- extern关键字用于第二次声明时不会改变其原有的属性(static int a;extern int a;还是internal属性);
这是static、extern对变量/函数的链接属性上的作用;
3.变量的作用域与存储类型
记住一点,变量类型的改变不会修改变量的作用域;侠义上讲变量的作用域就是定于的代码块;
变量的存储类型static,这个才是变量的存储类型,代表静态类型存储。
4.存储区域
a.静态数据区:
- 在编译器进行编译的时候就为该变量分配的内存,即全局变量和静态变量(用static声明的变量),
- 存放在这个区的数据程序全部执行结束后系统自动释放,声明周期贯穿于整个程序执行过程。
- 全局变量和静态变量的存储是放在一块的,
- 初始化的全局变量和静态变量在一块区域(.data),未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(.bss)。
b.堆区:
- 这部分存储空间完全由程序员自己负责管理,它的分配和释放都由程序员自己负责。
- 这个区是唯一一个可以由程序员自己决定变量生存期的区间。
- 可以用malloc,new申请堆内存,并通过free和delete释放空间。
- 如果程序员自己在堆区申请了空间,又忘记将这片内存释放掉,就会造成内存泄露的问题,导致后面一直无法访问这片存储区域。
- 但程序退出后,系统自动回收资源。分配方式倒是类似于链表。
c.栈区:
- 存放函数的形式参数和局部变量,
- 由编译器分配和自动释放,函数执行完后,局部变量和形参占用的空间会自动被释放。效
- 率比较高,但是分配的容量很有限。
d.常量区:
- 存放常量的区间,如字符串常量等,注意在常量区存放的数据一旦经初始化后就不能被修改。
- 程序结束后由系统释放。
最后,各区域的大小,申请速度、存取效率,见: