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語言中的用法一模一樣。...