內(nèi)存的分配與釋放

堆與棧

  • 堆是大家共有的空間,分全局堆和局部堆百新。全局堆就是所有沒有分配的空間薇缅,局部堆就是用戶分配的空間评也。堆在操作系統(tǒng)對進程初始化的時候分配,運行過程中也可以向系統(tǒng)要額外的堆锋玲,但是記得用完了要還給操作系統(tǒng)景用,要不然就是內(nèi)存泄漏。
  • 棧是線程獨有的惭蹂,保存其運行狀態(tài)和局部自動變量的伞插。棧在線程開始的時候初始化,每個線程的椂芡耄互相獨立媚污。每個函數(shù)都有自己的棧,棧被用來在函數(shù)之間傳遞參數(shù)廷雅。操作系統(tǒng)在切換線程的時候會自動的切換棧耗美,就是切換SS/ESP寄存器。棸窠危空間不需要在高級語言里面顯式的分配和釋放幽歼。
分配內(nèi)存時堆與棧的區(qū)別
  • 棧是由編譯器自動分配釋放,存放函數(shù)的參數(shù)值谬盐、局部變量的值等甸私。操作方式類似于數(shù)據(jù)結構中的棧

  • 堆一般由程序員分配釋放,若不釋放飞傀,程序結束時可能由OS回收皇型。注意這里說是可能诬烹,并非一定。再強調(diào)一次弃鸦,記得要釋放=视酢!唬格!

  • 棧區(qū)(stack) :
    編譯器自動分配釋放家破,主要存放函數(shù)的參數(shù)值,局部變量值等购岗。windows下汰聋,棧內(nèi)存分配是一個常數(shù),超出了限制喊积,提示stack overflow錯誤

  • 堆區(qū)(heap):程序員手動分配釋放烹困,操作系統(tǒng)80%內(nèi)存

  • 全局區(qū)或靜態(tài)區(qū):存放全局變量和靜態(tài)變量;程序結束時由系統(tǒng)釋放乾吻,分為全局初始化區(qū)和全局未初始化區(qū)

  • 字符常量區(qū):常量字符串放與此髓梅,程序結束時由系統(tǒng)釋放

  • 程序代碼區(qū):存放函數(shù)體的二進制代碼

示例如下:

int a = 0;          // 全局初始化區(qū)
char *p1;           // 全局未初始化區(qū)
int main(int argc, char** argv) {
    int b;                  // 棧
    char s[] = "abc";       // 棧
    char *p2;               // 棧
    char *p3 = "3210";      // 其中,"3210\0"常量區(qū)绎签,p3在棧區(qū)
    static int c = 0;       // 全局區(qū)
    p1 = (char*)malloc(20);         // 20個字節(jié)區(qū)域在堆區(qū)
    strcpy(p1, "3210");             // "3210\0" 在常量區(qū)枯饿,編譯器可能會優(yōu)化為和p3的指向同一塊區(qū)域
    return 0;
}

C語言中內(nèi)存分配與釋放

動態(tài)與靜態(tài)分配內(nèi)存
  • 靜態(tài)內(nèi)存分配,分配內(nèi)存大小的是固定辜御,問題:1.很容易超出棧內(nèi)存的最大值 2.為了防止內(nèi)存不夠用會開辟更多的內(nèi)存鸭你,容易浪費內(nèi)存

  • 動態(tài)內(nèi)存分配,在程序運行過程中擒权,動態(tài)指定需要使用的內(nèi)存大小袱巨,手動釋放,釋放之后這些內(nèi)存還可以被重新使用

malloc和free函數(shù)
  1. malloc僅僅分配內(nèi)存碳抄,free僅僅回收內(nèi)存愉老,并不執(zhí)行構造和析構函數(shù)
  2. malloc、free是函數(shù)剖效,可以覆蓋嫉入,C、C++中都可以使用
  3. malloc申請的內(nèi)存只能使用free釋放
  4. malloc和free是實現(xiàn)的函數(shù)璧尸,并不是C語言的標準
malloc咒林、calloc、realloc的使用
  • malloc() 函數(shù)
    用來動態(tài)地分配內(nèi)存空間爷光,原型為:void* malloc (size_t size);分配成功返回指向該內(nèi)存的地址垫竞,失敗則返回 NULL。

  • calloc() 函數(shù)
    用來動態(tài)地分配內(nèi)存空間并初始化為0,就是NULL欢瞪。原型為:void* calloc (size_t num, size_t size);活烙。calloc() 在內(nèi)存中動態(tài)地分配 num 個長度為 size 的連續(xù)空間,并將每一個字節(jié)都初始化為 0遣鼓。所以它的結果是分配了 num * size 個字節(jié)長度的內(nèi)存空間啸盏,并且每個字節(jié)的值都是0。分配成功返回指向該內(nèi)存的地址骑祟,失敗則返回 NULL回懦。

  • realloc() 函數(shù)
    重新分配內(nèi)存,原型為:realloc(void *__ptr, size_t __size);曾我,更改已經(jīng)配置的內(nèi)存空間粉怕,即更改由malloc()函數(shù)分配的內(nèi)存空間的大小健民。如果將分配的內(nèi)存減少抒巢,realloc僅僅是改變索引的信息。如果是將分配的內(nèi)存擴大秉犹,則有以下情況:
    1)如果當前內(nèi)存段后面有需要的足夠大內(nèi)存空間蛉谜,則直接擴展這段內(nèi)存空間,realloc()將返回原指針崇堵。
    2)如果當前內(nèi)存段后面的空閑字節(jié)不夠型诚,那么就使用堆中的第一個能夠滿足這一要求的內(nèi)存塊,將目前的數(shù)據(jù)復制到新的位置鸳劳,并將原來的數(shù)據(jù)塊釋放掉狰贯,返回新的內(nèi)存塊位置。
    3)如果申請失敗赏廓,將返回NULL涵紊,此時,原來的指針仍然有效幔摸。

注意:如果調(diào)用成功摸柄,不管當前內(nèi)存段后面的空閑空間是否滿足要求,都會釋放掉原來的指針既忆,重新返回一個指針驱负,雖然返回的指針有可能和原來的指針一樣,即不能再次釋放掉原來的指針患雇。

  • reallocf(), valloc()函數(shù)
    在mac系統(tǒng)中跃脊,還有這兩個函數(shù),不常用苛吱。原型為:
void* reallocf(void *ptr, size_t size);
void* valloc(size_t size);
  1. The valloc() function allocates size bytes of memory and returns a pointer to the allocated memory. The allocated memory is aligned on a page boundary.

  2. The reallocf() function is identical to the realloc() function, except that it will free the passed pointer when the requested memory cannot be allocated.
    This is a FreeBSD specific API designed to ease the problems with traditional coding styles for realloc causing memory leaks in libraries.

例子分析
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char** argv) {
    int a = 5;
    long b = 10;

    int * int_array = (int*)malloc(sizeof(int) * 8);
    printf("%ld\n", int_array);
    int_array[1] = 8;
    free(int_array);

    int * ints = (int*)malloc(sizeof(int) * 8);
    printf("%ld\n", ints);

    int * is = (int*)realloc(ints, sizeof(int) * 4);
    printf("%ld\n", is);

    int * iis = (int*)realloc(is, sizeof(int) * 16);
    printf("%ld\n", iis);

    //free(ints);
    //free(is);
    free(iis);

    return 0;
}

輸出結果如下:

由圖可知酪术,前三次的內(nèi)存地址輸出是一致的,第四次輸出了不一樣的內(nèi)存地址又谋。當然第二次的內(nèi)存地址跟第一次輸出的內(nèi)存地址一樣是因為編譯優(yōu)化的一些原因拼缝,大家可以嘗試不同gcc版本娱局,使用不同的-O級別。第三次輸出一致的內(nèi)存地址咧七,是因為新分配的內(nèi)存小于原來分配的內(nèi)存長度衰齐,于是內(nèi)存地址還是一樣的,但是原來的指針已經(jīng)被釋放掉了继阻。第四次則是內(nèi)存不足耻涛,所以重新分配到了一個新的內(nèi)存地址,原來的指針也沒釋放掉瘟檩。讀者可以把注釋的free代碼放開抹缕,自己編譯看一下結果。

C++的new與delete

C++中是通過new和delete操作符進行動態(tài)內(nèi)存管理墨辛。雖然是C++中的動態(tài)內(nèi)存管理卓研,但是與C語言中的四個函數(shù)不同,new和delete是C++中的操作符睹簇。標準中已經(jīng)定義好奏赘,由編譯器來實現(xiàn)分配和釋放內(nèi)存,不是函數(shù)庫里面的實現(xiàn)太惠,但是底層實現(xiàn)中也會調(diào)用基礎的malloc和free函數(shù)磨淌。

new/delete和malloc/free的區(qū)別和聯(lián)系:
  1. 它們都是動態(tài)管理內(nèi)存的入口
  2. malloc/free是C/C++標準庫的函數(shù),new/delete是C++操作符
  3. malloc/free只是動態(tài)分配內(nèi)存空間/釋放空間凿渊。而new/delete除了分配空間還會調(diào)用構造析構函數(shù)進行初始化與清理(清理成員)
  4. malloc/free需要手動計算類型大小且返回值為void*梁只,new/delete可自己計算類型的大小對應類型的指針
  5. new/delete的底層調(diào)用了malloc/free
  6. malloc/free申請空間后得判空,new/delete則不需要埃脏,之前是返回空指針搪锣,現(xiàn)在引發(fā)異常std:bad_alloc.
  7. new直接跟類型,malloc傳入節(jié)數(shù)個數(shù)
例子分析

1.C+11之前剂癌,可以初始化簡單變量:

int *p = new int(12);
delete p;
double *dp = new double(4.5);
delete[] dp;

2.C++11之后淤翔,可使用列表初始化:

struct point{double x,int y,doble z};
point *p = new point{1,2,3};
delete p;
int *array = new int []{1,2,3,4};
delete[] array;

3.使用new 和delete時,分別調(diào)用的是如下函數(shù):

void * operator new(std::size_t);
void * operator new[](std::size_t);
void * operator delete(std::size_t);
void * operator delete[](std::size_t);

例如1中的示例:

int *p = new int;
int *p = new (sizeof(int));

第三方不同的malloc/free實現(xiàn)

C語言的標準函數(shù)庫除了gcc libc之外佩谷,還有許多其他的實現(xiàn)旁壮。這里專門介紹一下malloc的其他實現(xiàn)。主要是ptmalloc,tcmalloc,jemalloc谐檀。這三種方式的實現(xiàn)各有自己的優(yōu)缺點:

1.作為基礎庫的ptmalloc是最為穩(wěn)定的內(nèi)存管理器抡谐,無論在什么環(huán)境下都能適應,但是分配效率相對較低
2.而tcmalloc針對多核情況有所優(yōu)化桐猬,性能有所提高麦撵,但是內(nèi)存占用稍高,大內(nèi)存分配容易出現(xiàn)CPU飆升
3.jemalloc的內(nèi)存占用更高,但是在多核多線程下的表現(xiàn)也最為優(yōu)異

具體需要使用哪一個庫免胃,需要按照自己的業(yè)務需求來音五,脫離業(yè)務需求談技術的都是耍流氓。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末羔沙,一起剝皮案震驚了整個濱河市躺涝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌扼雏,老刑警劉巖坚嗜,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異诗充,居然都是意外死亡苍蔬,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門蝴蜓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來碟绑,“玉大人,你說我怎么就攤上這事励翼◎诟遥” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵汽抚,是天一觀的道長。 經(jīng)常有香客問我伯病,道長造烁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任午笛,我火速辦了婚禮惭蟋,結果婚禮上,老公的妹妹穿的比我還像新娘药磺。我一直安慰自己告组,他們只是感情好,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布癌佩。 她就那樣靜靜地躺著木缝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪围辙。 梳的紋絲不亂的頭發(fā)上我碟,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機與錄音姚建,去河邊找鬼矫俺。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的厘托。 我是一名探鬼主播友雳,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼铅匹!你這毒婦竟也來了沥阱?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤伊群,失蹤者是張志新(化名)和其女友劉穎考杉,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舰始,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡崇棠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了丸卷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枕稀。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖谜嫉,靈堂內(nèi)的尸體忽然破棺而出萎坷,到底是詐尸還是另有隱情,我是刑警寧澤沐兰,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布哆档,位于F島的核電站,受9級特大地震影響住闯,放射性物質(zhì)發(fā)生泄漏瓜浸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一比原、第九天 我趴在偏房一處隱蔽的房頂上張望插佛。 院中可真熱鬧,春花似錦量窘、人聲如沸雇寇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锨侯。三九已至,卻和暖如春厘线,著一層夾襖步出監(jiān)牢的瞬間识腿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工造壮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留渡讼,地道東北人骂束。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像成箫,于是被迫代替她去往敵國和親展箱。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容