c 動態記憶體管理深入理解

2021-08-20 20:54:12 字數 3098 閱讀 6202

c++的動態記憶體管理

c語言用3個函式進行動態記憶體分配。

malloc申請一段連續的堆空間並返回首位址,不能初始化記憶體空間。

calloc會將分配到的空間每一位初始化為0,因此效率稍低。

realloc給乙個已經分配了位址的指標重新分配空間,realloc 擴大空間時,很有可能原有空間後的餘留空間不夠,需要進行三步操作,開闢一塊新的空間,拷貝原空間資料到新空間,釋放原空間。

最後都必須使用free對申請的空間進行釋放。

測試環境vs2010,debug版本

f11進入malloc函式,檢視c庫是怎麼實現的。不斷呼叫f11發現庫函式對malloc進行了多次封裝,最後進入dbheap.c檔案進行真正的堆空間申請。

首先找到一句堆上鎖的語句

_mlock(_heap_lock);

之後都是檢測堆校驗,檢測塊型別,重點是計算blocksize,這裡nsize是使用者真正需要建立的空間大小,後面乙個引數巨集定義為4,第乙個引數是乙個結構體。假定使用者nsize = 4執行完這一句blocksize=40.

blocksize = sizeof(_crtmemblockheader) + nsize + nnomanslandsize;

接下來系統用40去真正的申請一段堆空間。

phead = (_crtmemblockheader *)_heap_alloc_base(blocksize);

那麼額外的結構體和乙個4位元組的空間有什麼用呢?

結構體是用來管理和標記這塊記憶體空間的,多分配了4位元組用來隔離資料區。

/* fill in gap before and after real block */

memset((void *)phead->gap, _bnomanslandfill, nnomanslandsize);

memset((void *)(pbdata(phead) + nsize), _bnomanslandfill, nnomanslandsize);

/* fill data with silly value (but non-zero) */

memset((void *)pbdata(phead), _bcleanlandfill, nsize);

rtccallback(_rtc_funccheckset_hook,(1));

retval=(void *)pbdata(phead);

庫函式對使用者申請的空間前後用0xfd填充,真正的使用者資料區用0xcd填充。像是乙個柵欄一樣把使用者資料區隔離起來。

現在可以回答乙個問題了,free如何知道該釋放多少空間?

在前面的結構體中有乙個位置記錄了動態分配記憶體的大小。

在release版本實際分配的記憶體等於請求的記憶體大小,現在我們知道了在debug版本系統實際申請的堆空間要大於我們申請的空間,因此在做鍊錶節點申請時如果單個節點太小,會造成資源浪費的問題。

c++中通過new和delete運算子進行動態記憶體管理。

new和delete配套使用,如果用new申請了自定義型別物件date(有動態申請空間),卻使用free,那麼就有可能造成記憶體洩露。

class date

~date();

malloc/free是c庫函式,new/delete是c++的操作符

malloc/free只是動態分配記憶體空間/釋放空間。而new/delete除了分配空間還會呼叫建構函式和析構函式進行初始化與清理(清理成員)

malloc/free需要手動計算型別大小且返回值會void*,new/delete 可自己計算型別的大小,返回對應型別的指標

以下為vs2010的庫原始碼

new:

呼叫 operator new對malloc的封裝,如果申請失敗了就再次申請

// try to allocate size bytes

void *p;

while ((p = malloc(count)) == 0)

if (_callnewh(count) == 0)

return (p);

之後在已經申請的空間上呼叫建構函式

delete:

呼叫析構物件的析構函式,之後呼叫operator delete

同樣的在原始碼檔案找到了operator delete,是對free函式的封裝

void

operator

delete( void * p )

new:

void *__crtdecl operator

new(size_t count) _throw1(std::bad_alloc)

1.這裡呼叫的函式count為4+實際申請空間,多申請4位元組用來儲存物件的個數,之後呼叫operator new()。

2.在申請的空間上呼叫建構函式

3.物件個數放在空間前4位元組

4.空間首位址偏移4,返回使用者空間首位址

delete:

取出物件個數n

呼叫n次析構函式

釋放空間呼叫 operator delete (指標向前偏移4再呼叫operator delete)

對於乙個顯式定義了析構函式的test來說,以下方式釋放空間會有問題。

void test()

上文提到如果用new申請鍊錶節點,可知在每次實際的申請記憶體會比預期的大,這樣使用空間的效率就變的低了。若果預先分配一大段空間,然後每次從裡面取出一塊來使用就好了。在c++中通過定位new來實現。

#include 

#include

const

int chunk = 16;

class foo

foo()

private: int _val;

};// 預分配記憶體 但沒有foo物件

char *buf = new

char[ sizeof(foo) * chunk ];

int main()

深入理解C指標學習筆記七之動態記憶體管理

只針對額強大很大成都上源於它能追蹤動態分配的記憶體。通過指標來管理這部分記憶體是很多操作的基礎,包括一些用來處理複雜資料結構的操作。要完全利用這些能力,需要理解c的動態記憶體管理怎麼回事。c程式在執行時環境中執行,這通常是有作業系統提供的環境,支援堆和棧以及其他的程式行為。注意 c99引入了變長陣列...

深入剖析c 動態記憶體管理

首先先看下圖了解程式是怎樣在記憶體中管理的 1.棧又叫堆疊,非靜態區域性變數 函式引數 返回值等等,棧是向下增長的。2.記憶體對映段是高效的1o對映方式,用於裝載乙個共享的動態記憶體庫。使用者可使用系統介面建立共享共享記憶體,做程序間通訊。3.堆用於程式執行時動態記憶體分配,堆是可以上增長的 4.資...

C 動態記憶體管理

我們都知道在c 中可以用new malloc動態分配記憶體空間,delete free釋放動態開闢的記憶體空間。1.那麼既然c 中有了可以動態開闢記憶體的函式為什麼又要有new delete呢?c 中的malloc free是繼承c語言中的malloc free,它的用法和在c語言中的用法一模一樣。...