C/C++程序的内存分配与使用笔记
一、C/C++程序的内存分配
一个C/C++程序占用的内存区一般可以分为如下五种:
①全局/静态数据区
②常量数据区
③代码区
④堆
⑤栈
显然代码存放在代码区,而程序的数据则根据数据种类的不同放在不同的存储区中,在C/C++中,数据主要有几种不同的分类:常量和变量、全局数据和局部数据,静态数据与非静态数据,以及程序运行中产生和释放的动态数据。
其中
①全局/静态数据区中存储全局变量及静态变量(包括全局静态变量和局部静态变量);
②常量数据区中存储程序中的各种常量;
③栈中存储自动变量后者局部变量,以及传递的函数参数等
④堆是用户控制的存储区,存储动态产生的数据(new或者malloc)。
下面通过一个简单的实例来具体看看:
#include
#include
int g_nGlobal = 100;
int main()
{
char *pLocalString1 = "LocalString1";
const char *pLocalString2 = "LocalString2";
static int nLocalStatic = 0;
int nLocal = 0;
const int nLocalConst = 100;
int *pIntNew = new int[5];
char *pMalloc = (char *)malloc(1);
printf("global variable: 0x%x/n", &g_nGlobal);
printf("static variable: 0x%x/n", &nLocalStatic);
printf("local printer1: 0x%x/n", pLocalString1);
printf("local const printer: 0x%x/n/n", pLocalString2);
printf("new: 0x%x/n", pIntNew);
printf("malloc: 0x%x/n/n", pMalloc);
printf("local printer(pIntNew): 0x%x/n", &pIntNew);
printf("local printer(pLocalString1): 0x%x/n", &pLocalString1);
printf("local printer(pLocalString2): 0x%x/n", &pLocalString2);
printf("local variable(nLocal): 0x%x/n", &nLocal);
printf("local printer(pMalloc): 0x%x/n", &pMalloc);
printf("local const(nLocalConst): 0x%x/n", &nLocalConst);
delete []pIntNew;
free(pMalloc);
return 0;
}
实例共8个变量,包括一个全局变量g_nGlobal,1个局部静态变量nLocalStatic、以及6个局部变量。
在Windows XP 中使用VC2008编译运行,程序出处如下:
global variable: 0x417000
static variable: 0x417148
local printer1: 0x4158fc
local const printer: 0x4158ec
new: 0x383248
malloc: 0x383288
local printer(pIntNew): 0x12ff30
local printer(pLocalString1): 0x12ff60
local printer(pLocalString2): 0x12ff54
local variable(nLocal): 0x12ff48
local printer(pMalloc): 0x12ff24
local constvariable(nLocalConst): 0x12ff3c
从输出结果可以看出程序数据的分配情况。
通过new分配的位于堆上,5个int共20个字节,由于在堆上位16字节对齐,所以占用了32个字节从(48~88),内存对齐可是加速CPU对数据的访问,但是同时也造成了空间浪费,C/C++中的class、union和struct,可以通过#pragma pack()或者配置编译器来实现按要求对齐或者取消对齐。
程序的内存分配如下图:
全局/静态数据区 栈 堆
g_nGlobal pIntNew-->int[0..4]
nLocalStatic pMalloc--->char
… ….
"LocalString1"ß-------pLocalString1
"LocalString2"ß-------pLocalString2
nLocalConst
全局/静态数据区是在程序编译阶段都已经分配好的,在整个程序运行过程中始终存在,用来保存全局变量、静态变量、常量等。
其中字符串常量存储区域的数据是不可以修改的
例如
char *pLocalString1 = "LocalString1";
pLocalString1[1]= 'a';//试图修改不可修改的内存
二 堆和栈
虽然平常都是"堆栈堆栈"连着说的,但是他们的定义和作用是有区别的
在C/C++中,一个函数的内部变量以及传递给函数的参数等都是存储在栈中的。当退出这些变量的作用域时,这些栈的内容会被弹出释放。而是用malloc或者new申请的内存位于堆中,不会随着变量作用域的结束而自动释放,从而产生内存泄露。
例如实例中的
int *pIntNew = new int[5];
char *pMalloc = (char *)malloc(1);
pIntNew和pMalloc两个变量本身是位于栈的,当main()结束退出时,会被自动释放,而他们指向的内存在堆上,是不会自动释放的,因此造成内存泄露,所以必须显示的调用free或者delete。
这里产生一个问题:既然栈上的内存会自动释放不存在泄漏问题,而堆必须显示释放容易产生内存泄漏,为什么还要是用堆呢?
这是因为很多应用需要动态的管理数据,例如链表,而当需要新增节点插入链表时,此时就需要在堆上申请内存并插入节点。而且栈的大小也是有限制的,占用内存较多的对象只能在堆上分配。
除了以上的差别外,他们在大小和效率方面需要注意:
1、 大小
通常一个程序可以使用的栈的大小是固定的,由编译器决定。例如vc2008栈的默认大小就是1MB,当然可以修改它的大小,但是通常都不会很大。
int buf[1024*1024];//运行时会出错,栈溢出
但是堆的大小要比栈大很多,它主要受限与系统的虚拟内存的大小,可以分配比较大的数据。
2、效率
栈上的内存是系统自动分配的,pop与push都用相应的指令操作,因此效率比较高,而且分配的都是练习的内存空间,不会产生碎片。而堆上的内存是程序动态申请和释放的,系统需要通过一定的算法在堆空间中寻找合适的空间再进行分配,并修改相应的维护堆空间的链表,再返回地址给程序,因此效率比栈低,而且容易产生碎片。