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

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都用相应的指令操作,因此效率比较高,而且分配的都是练习的内存空间,不会产生碎片。而堆上的内存是程序动态申请和释放的,系统需要通过一定的算法在堆空间中寻找合适的空间再进行分配,并修改相应的维护堆空间的链表,再返回地址给程序,因此效率比栈低,而且容易产生碎片。

发布了62 篇原创文章 · 获赞 10 · 访问量 32万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章