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之外的數字才算真正的初始化)
具體原因不知道,只是猜測。
本文永久更新連結地址:https://www.bkjia.com/Linux/2018-03/151239.htm