1. 程式人生 > >C與C++的內存機制的比較

C與C++的內存機制的比較

內存;堆;棧

C語言與C++內存非常相似,這也是我一直搞不清楚他的原因;下面梳理一下他們之間的區別:

1、先說C語言的內存機制

    • 位於函數內的局部變量(包括函數實參),由編譯器負責分配和釋放,函數結束,棧變量失效;

    • 由程序員用malloc()/calloc()/realloc()分配空間,free()釋放所申請的空間。如果程序員忘記free(),則會造成內存泄漏,程序結束時可能會由操作系統回收,也許就一直占用著直至關機。

    • 全局區/靜態區 全局變量和靜態變量存放區,程序一經編譯好,該區域便存在。並且在C語言中初始化的全局變量和靜態變量和未初始化的放在相鄰的兩個區域在C++中,由於編譯器會給全局變量和靜態變量自動初始化賦值,所以沒有區分了)。由於全局變量一直占據內存空間且不易維護,推薦少用。程序結束時釋放。

    • C風格字符串常量存儲區 專門存放字符串常量的地方,程序結束時釋放;

    • 程序代碼區 存放程序二進制代碼的區域。


2、再說C++的內存機制

    • 位於函數內的局部變量(包括函數實參),由編譯器負責分配釋放,函數結束,棧變量失效。

    • 這裏與C不同的是,該堆是由new申請的內存,由delete負責釋放。

    • 自由存儲區 由程序員用malloc()/calloc()/realloc()分配空間,由free()釋放。如果程序員忘記free()了,則會造成內存泄漏,程序結束時可能會有操作系統回收,也許就一直占用著直至關機。 與C的堆機制對應。

    • 全局區/靜態區

      全局變量和靜態變量存放區,程序一經編譯好,該區域便存在。在C++中,由於編譯器會給全局變量和靜態變量自動初始化賦值,所以沒有區分初始化和未初始化變量。由於全局變量一直占據內存空間且不易維護,推薦少用。程序結束時釋放。

    • 常量存儲區 這是一塊比較特殊的存儲區,專門存儲不能修改的常量(如果采用非正常手段更改,當然也是可以的)。



下面舉個栗子,比較C與C++在全局區/靜態區的區別(Linux):

#include <stdio.h>

static int a;
int b;
int c = 1;

int main(void)
{
    return 0;
}

將文件編譯成可執行文件,打印文件的大小:

技術分享圖片

可以看到,數據段(data,不包括bss)為252,bss(未初始化數據段)為16;

接下來將測試代碼進行修改(對b進行初始化):

#include <stdio.h>

static int a;
int b = 1;
int c = 1;

int main(void)
{
    return 0;
}

將文件編譯成可執行文件,打印文件的大小:

技術分享圖片

可以看到,數據段(data,不包括bss)為256(252+4),bss(未初始化數據段)為12(16-4);


與上面的那段代碼對比可以發現,data增加了4,剛剛好是bss減少的4。現在,就可以確定C語言中,對全局區/靜態區中變量初始化與為初始化是放在不同區域的。

接下來看一下C++運行的結果:

b未手動初始化(int b;):

技術分享圖片

b手動初始化為0(int b = 0):

技術分享圖片

上面在C++下面,數據段(data)沒有變化;因此在c語言中,全局變量又分為初始化的和未初始化的,在c++裏面沒有這個區分了,他們共同占用同一塊內存區。


但是,這裏面有一個非常小的細節對於b的初始化,如果手動初始化為0以外的數字,打印出來的data段又與C語言是一樣的:

b初始化為1:

技術分享圖片

b不初始化:

技術分享圖片


以上問題的出現,是什麽原因,還沒有查清楚。

可能的原因是:

BSS段(bss segment)通常是指用來存放程序中未初始化的全局變量的一塊內存區域。(0也算未初始化)
數據段(data segment)通常是指用來存放程序中已初始化且不為0的全局變量的一塊內存區域。(只有初始化為0之外的數字才算真正的初始化)

具體原因不知道,只是猜測。


C與C++的內存機制的比較