關(guān)于C/C++內(nèi)存管理示例詳解
1、內(nèi)存分配方式
在C++中,內(nèi)存分成五個(gè)區(qū),分別是堆、棧、自由存儲(chǔ)區(qū)、靜態(tài)存儲(chǔ)區(qū)和常量存儲(chǔ)區(qū)。
1) 棧
執(zhí)行函數(shù)時(shí),函數(shù)內(nèi)局部變量的存儲(chǔ)單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時(shí)這些存儲(chǔ)單元自動(dòng)被釋放。棧內(nèi)存分配運(yùn)算內(nèi)置處理器指令集中,效率很高,但分配的內(nèi)存容量有限。
2) 堆
由new分配的內(nèi)存塊,釋放由程序員控制。如果程序員沒有釋放,那么就在程序結(jié)束的時(shí)候,被操作系統(tǒng)回收。
3) 自由存儲(chǔ)區(qū)
由malloc等分配的內(nèi)存塊,用free結(jié)束自己的生命。
4) 靜態(tài)存儲(chǔ)區(qū)
全局變量和靜態(tài)變量被分配到同一塊內(nèi)存中。C語言中,全局變量分為已初始化和未初始化。
5) 常量存儲(chǔ)區(qū)
里面存放的是常量,不允許修改。
2、堆和棧的區(qū)別
int * ptr = (int*)malloc(sizeof(int)*4);
在棧中存放了一個(gè)指向堆內(nèi)存的指針ptr。在程序會(huì)先確定在堆中分配內(nèi)存的大小,然后利用operator new分配內(nèi)存,然后放回這塊內(nèi)存的首地址,放在棧中。
1) 空間大小不同
在32位系統(tǒng)中,堆的空間是4G,而棧的空間很小。
2) 分配方式不同
堆是動(dòng)態(tài)分配的,沒有靜態(tài)分配。棧的靜態(tài)分配時(shí)編譯器完成的,動(dòng)態(tài)分配由alloca函數(shù)分配。棧的動(dòng)態(tài)分配由編譯器進(jìn)行釋放。
3) 管理方式不同
棧是由編譯器自動(dòng)管理。堆的釋放是由程序員控制。
4) 生長(zhǎng)方式不同
堆的生長(zhǎng)方式是向上的,向著內(nèi)存地址增加的方向。棧的生長(zhǎng)方式是向下的,是向著內(nèi)存地址減小的方向。
5) 能否產(chǎn)生碎片
對(duì)于堆,頻繁的new/delete會(huì)造成內(nèi)存空間的不連續(xù),從而造成大量的碎片,使程序效率降低。
6) 分配效率不同
棧是機(jī)器系統(tǒng)系統(tǒng)的數(shù)據(jù)結(jié)構(gòu),計(jì)算機(jī)會(huì)在底層對(duì)棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執(zhí)行,這就決定棧的效率比較高。
堆是C/C++函數(shù)庫提供的,庫函數(shù)會(huì)按照一定的算法,在堆內(nèi)存中搜索可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由于內(nèi)存碎片太多),就有可能調(diào)用系統(tǒng)功能去增加程序數(shù)據(jù)段的內(nèi)存空間,這樣就有機(jī)會(huì)分到足夠大小的內(nèi)存,然后進(jìn)行返回。
3、operator new和operator delete
3.1 為什么要進(jìn)行重載?
在嵌入式系統(tǒng)中,由于內(nèi)存的限制,頻繁的動(dòng)態(tài)分配不定大小的內(nèi)存會(huì)引起很大的問題以及堆破碎的風(fēng)險(xiǎn)。
當(dāng)你必須要使用new和delete的時(shí)候,你不得不控制C++中的內(nèi)存分配。你需要用重載的全局new和delete代替系統(tǒng)的內(nèi)存分配符。需要給類重載new和delete。
一個(gè)防止內(nèi)存破碎的方法是從不同固定大小的內(nèi)存池中分配不同類型的對(duì)象。對(duì)單個(gè)類重載new和delete,你就可以靈活的控制內(nèi)存分配。
3.2 重載全局的new和delete操作符
void* operator new(size_t size) { void* p = malloc(size); return (p); } void operator delete(void*p) { free(p); }
3.3 類重載new和delete
為單個(gè)類重載new和delete
class TestClass { public: void* operator new(size_t size) { void* p = malloc(size); return p; } void operator delete(void* p) { free(p); } };
為單個(gè)類重載new[] 和 delete[]
class TestClass { public: void* operator new[](size_t size) { void* p = malloc(size); return p; } void* operator delete[](void* p) { free(p); } } int main() { TestClass* p = new TestClass[10]; delete [] p; return 0; }
注意:new[] 中的個(gè)數(shù)參數(shù)是數(shù)組的大小加上額外的存儲(chǔ)對(duì)象數(shù)目的字節(jié)??紤]到內(nèi)存分配機(jī)制的因素,盡量避免使用對(duì)象數(shù)組。
4、有了malloc/free為什么還要new/delete
malloc和free是C/C++語言的標(biāo)準(zhǔn)庫函數(shù),new / delete是C++ 的運(yùn)算符。都用于申請(qǐng)動(dòng)態(tài)內(nèi)存和釋放內(nèi)存。
malloc / free 無法滿足動(dòng)態(tài)對(duì)象的要求。對(duì)象在創(chuàng)建的同時(shí)同時(shí)自動(dòng)執(zhí)行構(gòu)造函數(shù),對(duì)象消亡之前自動(dòng)執(zhí)行析構(gòu)函數(shù)。即就是C++語言需要一個(gè)能完成動(dòng)態(tài)內(nèi)存分配和初始化工作的運(yùn)算符new,以及一個(gè)能完成清理和釋放內(nèi)存工作的運(yùn)算符delete。
內(nèi)部數(shù)據(jù)類型的對(duì)象沒有析構(gòu)和構(gòu)造的過程,所以對(duì)于他們來說malloc / free和new / delete是等價(jià)的。
5、內(nèi)存耗盡的三種解決方法
在申請(qǐng)動(dòng)態(tài)內(nèi)存時(shí),找不到足夠大的內(nèi)存塊,malloc和new將返回NULL指針。
1)判斷指針是否為NULL,如果是則使用 return 終止函數(shù)
2)判斷指針是否為NULL,如果是則使用 exit(1) 終止程序
3)為malloc和new 設(shè)置異常處理函數(shù) 。
總結(jié)
到此這篇關(guān)于C/C++內(nèi)存管理的文章就介紹到這了,更多相關(guān)C/C++內(nèi)存管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++中char*轉(zhuǎn)換為L(zhǎng)PCWSTR的解決方案
最近在學(xué)習(xí)C++,遇到了一個(gè)char*轉(zhuǎn)換為L(zhǎng)PCWSTR的問題,通過查找資料終于解決了,所以下面這篇文章主要介紹了C++中char*轉(zhuǎn)LPCWSTR的解決方案,文中通過詳細(xì)的示例代碼介紹的很詳細(xì),有需要的朋友可以參考借鑒,下面來一起看看吧。2017-01-01Java C++ 題解leetcode1619刪除某些元素后數(shù)組均值
這篇文章主要為大家介紹了Java C++ 題解leetcode1619刪除某些元素后數(shù)組均值示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09QT實(shí)現(xiàn)簡(jiǎn)單計(jì)算器功能
這篇文章主要為大家詳細(xì)介紹了QT實(shí)現(xiàn)簡(jiǎn)單計(jì)算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04