一文詳解C++中動態(tài)內(nèi)存管理_第1頁
一文詳解C++中動態(tài)內(nèi)存管理_第2頁
一文詳解C++中動態(tài)內(nèi)存管理_第3頁
一文詳解C++中動態(tài)內(nèi)存管理_第4頁
一文詳解C++中動態(tài)內(nèi)存管理_第5頁
已閱讀5頁,還剩7頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第一文詳解C++中動態(tài)內(nèi)存管理目錄前言1、C/C++程序的內(nèi)存開辟2.C語言中動態(tài)內(nèi)存管理方式:malloc/calloc/realloc/free2.1malloc、calloc、realloc區(qū)別?3.C++內(nèi)存管理方式3.1new/delete操作內(nèi)置類型3.2new和delete操作自定義類型3.3new和malloc處理失敗4.operatornew與operatordelete函數(shù)4.1operatornew與operatordelete函數(shù)4.1.1我們看看operatornew庫里面的源碼4.1.2operatordelete庫里面的源碼4.1.3operatornew和operatordelete的價值(重點)4.2重載operatornew與operatordelete(了解)5.new和delete的實現(xiàn)原理5.1內(nèi)置類型5.2自定義類型5.2.1new原理5.2.2delete原理5.2.3newT[N]原理5.2.4delete[]原理6.malloc/free和new/delete的異同6.1malloc/free和new/delete的共同點6.2malloc/free和new/delete的不同點

前言

在我們?nèi)粘懘a的過程中,我們對內(nèi)存空間的需求有時候在程序運行的時候才能知道,這時候我們就需要使用動態(tài)開辟內(nèi)存的方法。

1、C/C++程序的內(nèi)存開辟

首先我們先了解一下C/C++程序內(nèi)存分配的幾個區(qū)域:

intglobalVar=1;

staticintstaticGlobalVar=1;

voidTest()

staticintstaticVar=1;

intlocalVar=1;

intnum1[10]={1,2,3,4};

charchar2[]="abcd";

constchar*pChar3="abcd";

int*ptr1=(int*)malloc(sizeof(int)*4);

int*ptr2=(int*)calloc(4,sizeof(int));

int*ptr3=(int*)realloc(ptr2,sizeof(int)*4);

free(ptr1);

free(ptr3);

}

1.棧區(qū)(stack):在執(zhí)行函數(shù)時,函數(shù)內(nèi)局部變量的存儲單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時這些存儲單元自動被釋放。棧內(nèi)存分配運算內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限。棧區(qū)主要存放運行函數(shù)而分配的局部變量、函數(shù)參數(shù)、返回數(shù)據(jù)、返回地址等。2.堆區(qū)(heap):一般由程序員分配釋放,若程序員不釋放,程序結(jié)束時可能由OS回收。分配方式類似于鏈表。3.數(shù)據(jù)段(靜態(tài)區(qū))(static)存放全局變量、靜態(tài)數(shù)據(jù)。程序結(jié)束后由系統(tǒng)釋放。4.代碼段:存放函數(shù)體(類成員函數(shù)和全局函數(shù))的二進(jìn)制代碼。

這幅圖中,我們可以發(fā)現(xiàn)普通的局部變量是在棧上分配空間的,在棧區(qū)中創(chuàng)建的變量出了作用域去就會自動銷毀。但是被static修飾的變量是存放在數(shù)據(jù)段(靜態(tài)區(qū)),在數(shù)據(jù)段上創(chuàng)建的變量直到程序結(jié)束才銷毀,所以數(shù)據(jù)段上的數(shù)據(jù)生命周期變長了。

2.C語言中動態(tài)內(nèi)存管理方式:malloc/calloc/realloc/free

在C語言中,我們經(jīng)常會用到malloc,calloc和realloc來進(jìn)行動態(tài)的開辟內(nèi)存;同時,C語言還提供了一個函數(shù)free,專門用來做動態(tài)內(nèi)存的釋放和回收。其中他們?nèi)齻€的區(qū)別也是我們需要特別所強調(diào)區(qū)別的。

2.1malloc、calloc、realloc區(qū)別?

malloc函數(shù)是向內(nèi)存申請一塊連續(xù)可用的空間,并返回指向這塊空間的指針。

calloc與malloc的區(qū)別只在于calloc會在返回地址之前把申請的空間的每個字節(jié)初始化為0。

realloc函數(shù)可以做到對動態(tài)開辟內(nèi)存大小的調(diào)整。

我們通過這三個函數(shù)的定義也可以進(jìn)行功能的區(qū)分:

voidTest()

int*p1=(int*)malloc(sizeof(int));

free(p1);

int*p2=(int*)calloc(4,sizeof(int));

int*p3=(int*)realloc(p2,sizeof(int)*10);

free(p3);

}

3.C++內(nèi)存管理方式

我們都知道,C++語言是兼容C語言的,因此C語言中內(nèi)存管理方式在C++中可以繼續(xù)使用。但是有些地方就無能為力了,并且使用起來也可能比較麻煩。因此,C++擁有自己的內(nèi)管管理方式:通過new和delete操作符進(jìn)行動態(tài)內(nèi)存管理。

3.1new/delete操作內(nèi)置類型

intmain()

//動態(tài)申請一個int類型的空間

int*ptr1=newint;

//動態(tài)申請一個int類型的空間并初始化為10

int*ptr2=newint(10);

//動態(tài)申請3個int類型的空間(數(shù)組)

int*ptr3=newint[3];

//動態(tài)申請3個int類型的空間,初始化第一個空間值為1

int*ptr4=newint[3]{1};

deleteptr1;

deleteptr2;

delete[]ptr3;

delete[]ptr4;

return0;

}

我們首先通過畫圖分析進(jìn)行剖析代碼:

我們在監(jiān)視窗口看看這3個變量

注意:申請和釋放單個元素的空間,使用new和delete操作符,申請和釋放連續(xù)的空間,使用new[]和delete[],要匹配起來使用。

3.2new和delete操作自定義類型

classA{

public:

A(inta=0)

:_a(a)

cout"A():"thisendl;

cout"~A():"thisendl;

private:

int_a;

intmain()

A*p1=(A*)malloc(sizeof(A));

A*p2=newA(1);

free(p1);

deletep2;

return0;

}

在這段代碼中,p1是我們使用malloc開辟的,p2是通過new來開辟的。我們編譯運行這段代碼。

發(fā)現(xiàn)輸出了這兩句,那這兩句是誰調(diào)用的呢我們通過調(diào)試逐語句來分析這個過程

內(nèi)置類型區(qū)別

注意:在申請自定義類型的空間時,new會自動調(diào)用構(gòu)造函數(shù),delete時會調(diào)用析構(gòu)函數(shù),而malloc和free不會。

3.3new和malloc處理失敗

intmain()

void*p0=malloc(1024*1024*1024);

coutp0endl;

//malloc失敗,返回空指針

void*p1=malloc(1024*1024*1024);

coutp1endl;

//new失敗,拋異常

void*p2=newchar[1024*1024*1024];

coutp2endl;

catch(constexceptione)

coute.what()endl;

return0;

}

我們能夠發(fā)現(xiàn),malloc失敗時會返回空指針,而new失敗時,會拋出異常。

4.operatornew與operatordelete函數(shù)

4.1operatornew與operatordelete函數(shù)

C++標(biāo)準(zhǔn)庫還提供了operatornew和operatordelete函數(shù),但是這兩個函數(shù)并不是對new和delete的重載,operatornew和operatordelete是兩個庫函數(shù)。(這里C++大佬設(shè)計時這樣取名確實很容易混淆)

4.1.1我們看看operatornew庫里面的源碼

void*__CRTDECLoperatornew(size_tsize)_THROW1(_STDbad_alloc){

//trytoallocatesizebytes

void*p;

while((p=malloc(size))==0)

if(_callnewh(size)==0)

//reportnomemory

//如果申請內(nèi)存失敗了,這里會拋出bad_alloc類型異常

staticconststd::bad_allocnomem;

_RAISE(nomem);

return(p);

}

庫里面operatornew的作用是封裝了malloc,如果malloc失敗,拋出異常。

4.1.2operatordelete庫里面的源碼

該函數(shù)最終是通過free來釋放空間的

//operatordelete源碼

voidoperatordelete(void*pUserData){

_CrtMemBlockHeader*pHead;

RTCCALLBACK(_RTC_Free_hook,(pUserData,0));

if(pUserData==NULL)

return;

_mlock(_HEAP_LOCK);/*blockotherthreads*/

__TRY

/*getapointertomemoryblockheader*/

pHead=pHdr(pUserData);

/*verifyblocktype*/

_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead-nBlockUse));

_free_dbg(pUserData,pHead-nBlockUse);

__FINALLY

_munlock(_HEAP_LOCK);/*releaseotherthreads*/

__END_TRY_FINALLY

return;

free的實現(xiàn)

#definefree(p)_free_dbg(p,_NORMAL_BLOCK)

4.1.3operatornew和operatordelete的價值(重點)

classA{

public:

A(inta=0)

:_a(a)

cout"A():"thisendl;

cout"~A():"thisendl;

private:

int_a;

intmain()

//跟malloc功能一樣,失敗以后拋出異常

A*ps1=(A*)operatornew(sizeof(A));

operatordelete(ps1);

A*ps2=(A*)malloc(sizeof(A));

free(ps2);

A*ps3=newA;

deleteps3;

return0;

}

我們使用new的時候,new要開空間,要調(diào)用構(gòu)造函數(shù)。new可以轉(zhuǎn)換成callmalloc,call構(gòu)造函數(shù)。但是callmalloc一旦失敗,會返回空指針或者錯誤碼。在面向?qū)ο蟮恼Z言中更喜歡使用異常。而operatornew相比較malloc的不同就在于如果一旦失敗會拋出異常,因此new的底層實現(xiàn)是調(diào)用operatornew,operatornew會調(diào)用malloc(如果失敗拋出異常),再調(diào)用構(gòu)造函數(shù)。

我們通過匯編看一下ps3

operatordelete同理。

總結(jié):通過上述兩個全局函數(shù)的實現(xiàn)知道,operatornew實際也是通過malloc來申請空間,如果malloc申請空間成功就直接返回,否則執(zhí)行用戶提供的空間不足應(yīng)對措施,如果用戶提供該措施就繼續(xù)申請,否則就拋異常。operatordelete最終是通過free來釋放空間的。

4.2重載operatornew與operatordelete(了解)

專屬的operatornew技術(shù),提高效率。應(yīng)用:內(nèi)存池

classA{

public:

A(inta=0)

:_a(a)

cout"A():"thisendl;

//專屬的operatornew

void*operatornew(size_tn)

void*p=nullptr;

p=allocatorA().allocate(1);

cout"memorypoolallocate"endl;

returnp;

voidoperatordelete(void*p)

allocatorA().deallocate((A*)p,1);

cout"memorypooldeallocate"endl;

cout"~A():"thisendl;

private:

int_a;

intmain()

intn=0;

cinn;

for(inti=0;i++i)

A*ps1=newA;//operatornew+A的構(gòu)造函數(shù)

return0;

}

注意:一般情況下不需要對operatornew和operatordelete進(jìn)行重載,除非在申請和釋放空間時候有某些特殊的需求。比如:在使用new和delete申請和釋放空間時,打印一些日志信息,可以簡單幫助用戶來檢測是否存在內(nèi)存泄漏。

5.new和delete的實現(xiàn)原理

5.1內(nèi)置類型

如果申請的是內(nèi)置類型的空間,new和malloc,delete和free基本類似,不同的地方是:new/delete申請和釋放的是單個元素的空間,new[]和delete[]申請的是連續(xù)空間,而且new在申請空間失敗時會拋異常,malloc會返回NULL。

5.2自定義類型

5.2.1new原理

1、調(diào)用operatornew函數(shù)申請空間2、再調(diào)用構(gòu)造函數(shù),完成對對象的構(gòu)造。

5.2.2delete原理

1、先調(diào)用析構(gòu)函數(shù),完成對對象中資源的清理工作。2、調(diào)用operatordelete函數(shù)釋放對象的空間

5.

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論