最近发现一个很有趣的事情,就是全局变量、全局静态变量、局部静态变量、局部变量中变量的释放顺序。下述均属Linux x86_64系统下C++的运行情况。
一、内存分布
众所周知,一个进程的内存空间主要分为:栈内存、堆内存、数据段、和代码段,另外内核区和不可访问区不在此讲述。

1.栈内存
栈的全称是“运行时栈(Run-time Stack)”,顾名思义就是随着程序运行、变量的进栈和出栈而不断改变。局部变量存放在该位置。
2堆内存.
堆内存是一块自由内存,由用户来申请和释放。堆内存全称是“运行时堆(Run-time Heap)”,和栈一样内存大小随着程序的运行而变化。
3.数据段
数据段包含三个部分,地址由低到高分别是:bss段、data段、rodata段。其中bss是存放未初始化的静态数据(系统自动初始化为0,节省磁盘空间),data是存放已初始化的静态数据,rodata是存放只读数据,比如字符串、字符常量等。所谓静态数据,包括全局变量和static关键字修饰的变量。
4.代码段
代码段分为两个部分:text段和init段。text段用来存放用户程序代码,而init段则用来存储系统给每一个可执行程序自动添加的“初始化”代码,这部分代码功能包括环境变量的准备、命令行参数的组织和传递等,并且这部分数据被放在了栈底。
总结:
int a; //全局变量,存放在bss段
static int b=1; //全局静态变量,存放在data段
int main()
{
int c; //局部变量,存放在栈
int * p = (int *)malloc(4); //存放在堆
static int d; //局部静态变量,存放在数据段的bss
free(p);
return 0;
}
二、变量释放顺序
声明定义了四个类,分别是A、B、C、D,每个类重写析构函数,用来判断内存释放顺序,代码如下:
#include <iostream>
using namespace std;
class A{
public:
~A(){
cout << "A释放内存" << endl;
}
};
class B{
public:
~B(){
cout << "B释放内存" << endl;
}
};
class C{
public:
~C(){
cout << "C释放内存" << endl;
}
};
class D{
public:
~D(){
cout << "D释放内存" << endl;
}
};
//主函数具体代码如下:
1、相同变量类型,先声明的后释放。

2、不同变量类型,释放顺序与位置无关,与变量类型有关。

static变量的生命周期为整个程序,如图static和局部变量在同一作用域内,局部变量比static变量先释放内存。

上图说明不管是普通全局变量还是静态全局变量,其顺序只看声明定义顺序。而局部静态变量和全局静态变量相比,局部静态变量先释放内存。
3、由用户申请的堆内存,在用户手动释放的时候释放,若没有释放,会造成内存泄漏。
总结:
1)同类型变量(此处类型为:全局变量、局部变量、静态变量)下,先声明定义的后释放内存。
2)不同类型变量顺序为:普通局部变量>静态局部变量>全局变量。
3)静态全局变量和普通全局变量归为第一点。
三、举例子
如图:在同一作用域下,验证到优先级为:普通全局变量>静态全局变量>普通全局变量,由用户申请的内存使用delete的时候释放。


本文探讨了Linux x86_64系统下C++程序中不同类型的变量(全局、静态、局部)在内存中的分布以及释放顺序。栈内存存放局部变量,堆内存由用户管理,数据段包括bss、data和rodata段,代码段包含text和init段。全局变量和静态变量在数据段,局部变量在栈,堆内存由malloc分配并在free时释放。变量释放顺序遵循声明定义的逆序,局部静态变量先于全局变量释放。总结了内存释放的三条原则,并通过实例验证了释放顺序:局部变量>静态局部变量>全局变量。
695

被折叠的 条评论
为什么被折叠?



