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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章