您的位置:首页 > 编程语言 > C语言/C++

C/C++程序的内存分配与使用笔记

2011-06-12 20:26 309 查看
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都用相应的指令操作,因此效率比较高,而且分配的都是练习的内存空间,不会产生碎片。而堆上的内存是程序动态申请和释放的,系统需要通过一定的算法在堆空间中寻找合适的空间再进行分配,并修改相应的维护堆空间的链表,再返回地址给程序,因此效率比栈低,而且容易产生碎片。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: