C語(yǔ)言的動(dòng)態(tài)內(nèi)存管理你了解嗎
C/C++內(nèi)存分配方式
在學(xué)習(xí)C語(yǔ)言階段的時(shí)候,創(chuàng)建一個(gè)變量,編譯器會(huì)為它分配一塊內(nèi)存。而創(chuàng)建一個(gè)C++對(duì)象的時(shí)候,編譯器會(huì)為這個(gè)對(duì)象分配內(nèi)存,并且調(diào)用合適的構(gòu)造函數(shù)進(jìn)行初始化。
那么編譯器的內(nèi)存分配方式是怎樣的呢?
內(nèi)存分配可以有以下的幾種方式
- 從靜態(tài)存儲(chǔ)區(qū)分配。這樣的分配方式在程序開(kāi)始前就可以為對(duì)象/變量分配,這塊空間在整個(gè)程序運(yùn)行期間都存在。
- 從棧區(qū)分配。調(diào)用函數(shù)時(shí),函數(shù)的參數(shù),局部變量,返回地址等存儲(chǔ)在堆棧上,函數(shù)執(zhí)行結(jié)束時(shí)將會(huì)自動(dòng)釋放這些內(nèi)存空間,棧區(qū)的內(nèi)存空間遠(yuǎn)遠(yuǎn)小于堆區(qū)。
- 從堆區(qū)分配。這種內(nèi)存分配方式被稱為動(dòng)態(tài)內(nèi)存分配,堆區(qū)又被稱為“自由存儲(chǔ)單元”,運(yùn)行時(shí)通過(guò)調(diào)用相應(yīng)的函數(shù)來(lái)申請(qǐng)和釋放內(nèi)存。
有時(shí)候我們并不知道程序中的對(duì)象確切地需要多少內(nèi)存空間,動(dòng)態(tài)內(nèi)存分配則很好地處理了這種需求。
C++內(nèi)存管理方式
C庫(kù)中提供了函數(shù)malloc,以及它的變種函數(shù)realloc、calloc來(lái)動(dòng)態(tài)地申請(qǐng)內(nèi)存空間。使用函數(shù)free來(lái)釋放動(dòng)態(tài)申請(qǐng)出的內(nèi)存空間。
int* ptr1 = (int*)malloc(sizeof(int));
使用malloc需要指定空間大小,并且要強(qiáng)制類型轉(zhuǎn)化,因?yàn)樗皇呛?jiǎn)單地分配了一塊空間,返回的是void*,而C++中不允許將空類型的指針賦予給其他類型的指針。另外,如果你申請(qǐng)一塊內(nèi)存之后,沒(méi)有對(duì)這個(gè)指針進(jìn)行正確的初始化,有可能會(huì)導(dǎo)致程序運(yùn)行失敗,并且如果忘記釋放動(dòng)態(tài)申請(qǐng)的內(nèi)存空間,則會(huì)造成內(nèi)存泄露等危害……
在創(chuàng)建一個(gè)C++對(duì)象時(shí),編譯器會(huì)做這兩件事:
1.為對(duì)象分配內(nèi)存。
2.編譯器自動(dòng)調(diào)用構(gòu)造函數(shù)初始化該內(nèi)存。
構(gòu)造函數(shù)不支持顯式地調(diào)用,意味著如果使用malloc函數(shù)創(chuàng)建一個(gè)對(duì)象,那么這個(gè)對(duì)象將不能夠調(diào)用構(gòu)造函數(shù),僅僅只是開(kāi)辟了一塊空間。但是我們必須要確保對(duì)象被初始化,因?yàn)槲闯跏蓟瘜?duì)象是大部分程序出錯(cuò)的主要原因??偠灾?,C中的動(dòng)態(tài)內(nèi)存管理無(wú)法滿足C++中動(dòng)態(tài)對(duì)象的需求。
所以提出了new和delete.關(guān)鍵字
new和delete的使用
int main(void) { //基本內(nèi)置類型 //開(kāi)辟一個(gè)int類型的空間 int* ptr2 = new int; //開(kāi)辟多個(gè)int類型空間 int* ptr3 = new int[5]; //開(kāi)辟一個(gè)int類型并初始化為1 int* ptr4 = new int(1); delete ptr2; delete[] ptr3; delete ptr4; return 0; }
new和delete的使用方式:
1.開(kāi)辟一個(gè)空間: new 類型; 對(duì)應(yīng)釋放: delete 對(duì)象;2.開(kāi)辟多個(gè)空間:new 類型[個(gè)數(shù)] 對(duì)應(yīng)釋放:delete[] 對(duì)象;3.開(kāi)辟并初始化: new 類型(初始化數(shù)據(jù)) 對(duì)應(yīng)釋放:delete 對(duì)象 1.開(kāi)辟一個(gè)空間: new 類型; 對(duì)應(yīng)釋放: delete 對(duì)象; 2.開(kāi)辟多個(gè)空間:new 類型[個(gè)數(shù)] 對(duì)應(yīng)釋放:delete[] 對(duì)象; 3.開(kāi)辟并初始化: new 類型(初始化數(shù)據(jù)) 對(duì)應(yīng)釋放:delete 對(duì)象
new和delete的騷操作
內(nèi)置類型
對(duì)于內(nèi)置類型,new和delete與C的內(nèi)存管理函數(shù)做了差不多的事情,不同的地方是:new/delete申請(qǐng)和釋放的是單個(gè)元素的空間,new[]和delete[]申請(qǐng)的是連續(xù)空間,而且new在申請(qǐng)空間失敗時(shí)會(huì)拋異常,malloc會(huì)返回NULL。
自定義類型
new表達(dá)式:
- 調(diào)用opreator new函數(shù)分配內(nèi)存
- 調(diào)用構(gòu)造函數(shù)初始化該內(nèi)存
delete表達(dá)式:
- 調(diào)用析構(gòu)函數(shù)清理對(duì)象中的資源
- 調(diào)用operator delete釋放空間。
operator new( ) 和operator delete( )這兩個(gè)內(nèi)存分配函數(shù)是系統(tǒng)提供的全局函數(shù),實(shí)際上是對(duì)malloc和free的各種行為進(jìn)行了封裝。
new和delete的區(qū)別
new、delete 和 malloc、free的區(qū)別有哪些呢?
- new和delete是關(guān)鍵字,malloc和free是函數(shù)
- malloc申請(qǐng)的空間不會(huì)初始化,new會(huì)初始化。
- malloc需要手動(dòng)計(jì)算空間大小并傳遞,new不需要
- malloc的返回值是void*,使用時(shí)必須強(qiáng)制類型轉(zhuǎn)換;new不需要,后面跟的是空間的類型。
- malloc申請(qǐng)失敗,返回NULL,所以調(diào)用后要判斷是否開(kāi)辟成功;new需要捕獲異常
- malloc只是開(kāi)辟空間,不會(huì)調(diào)用構(gòu)造函數(shù),free釋放空間不會(huì)調(diào)用析構(gòu)函數(shù);new在申請(qǐng)空間后會(huì)調(diào)用構(gòu)造函數(shù)初始化對(duì)允許象,delete會(huì)調(diào)用析構(gòu)函數(shù)清理對(duì)象中的資源,然后再釋放空間。
重載new和delete
C++允許重載new和delete,以實(shí)現(xiàn)我們自己的存儲(chǔ)分配方案。但是注意重載operator new和operator delete時(shí),僅僅只能改變?cè)镜膬?nèi)存分配方式。同重載其他的運(yùn)算符一樣,可以分為重載成全局和針對(duì)特定類的內(nèi)存分配函數(shù)。
重載全局
重載一個(gè)全局的new和delete會(huì)導(dǎo)致默認(rèn)版本完全不能被訪問(wèn)。
重載operator new的要求:
- 必須有一個(gè)size_t參數(shù),該參數(shù)將接收要開(kāi)辟空間的長(zhǎng)度。
- 返回一個(gè)指向?qū)ο蟮闹羔?,該?duì)象的長(zhǎng)度等于或者大于所申請(qǐng)的長(zhǎng)度。
- 如果分配失敗,不僅僅要返回一個(gè)0,還需產(chǎn)生一個(gè)異常信息之類的現(xiàn)象,明確分配內(nèi)存時(shí)出了問(wèn)題。
- 返回值是一個(gè)void*
重載operator delete的要求
- 參數(shù)是一個(gè)指向由operator new()分配的void*類型的內(nèi)存的指針
- 返回值是void
為什么重載operator delete的時(shí)候,參數(shù)是一個(gè)void*?
這是因?yàn)樗窃谡{(diào)用析構(gòu)函數(shù)后得到的指針。
//重載operator new //1.必須有一個(gè)size_t的參數(shù),該參數(shù)將接收要申請(qǐng)開(kāi)辟空間的大小 //2.返回值是一個(gè)void* //3.返回一個(gè)指向?qū)ο蟮闹羔?,該?duì)象的長(zhǎng)度等于或大于所申請(qǐng)的長(zhǎng)度 //4.如果分配失敗。不僅僅要返回一個(gè)0,還需產(chǎn)生一個(gè)異常信息 void* operator new(size_t sz) { cout << "new %d Bytes" << sz << endl; void* p = nullptr; //不需要強(qiáng)制類型轉(zhuǎn)換,因?yàn)閙alloc返回的就是void* p = malloc(sz); if (nullptr == p) { cout << "new fail\n" << endl; } return p; } //重載operator delete //1.返回值為void //2.參數(shù)是一個(gè)指向由operator new()返回的void*的指針 void operator delete(void* rp) { cout << "operator delete" << endl; free(rp); }
重載類專屬
//重載ListNode專屬的operator new struct ListNode { ListNode* _next; ListNode* _prev; int _data; void* operator new(size_t n) { void* p = nullptr; p = allocator<ListNode>().allocate(1); cout << "memory pool allocate" << endl; return p; } void operator delete(void* p) { allocator<ListNode>().deallocate((ListNode*)p, 1); //內(nèi)存池--空間適配器 cout << "memory pool deallocate" << endl; } }; class List { public: List() { _head = new ListNode; _head->_next = _head; _head->_prev = _head; } ~List() { ListNode* cur = _head->_next; while (cur != _head) { ListNode* next = cur->_next; delete cur; cur = next; } delete _head; _head = nullptr; } private: ListNode* _head; }; int main() { List l; return 0; }
定位new表達(dá)式
定位new表達(dá)式:它的作用是在已分配的原始內(nèi)存空間中用構(gòu)造函數(shù)初始化一個(gè)對(duì)象
使用的格式:
new (place_address) type 或者 new (place_address) type (initializer-lost) place_address
必須是一個(gè)指針,initializer-list
是初始化列表。
//例如 class Test { public: Test() : _data(0) { cout << "Test():" << this << endl; } ~Test() { cout << "~Test():" << this << endl; } private: int _data; }; int main(void) { // pt現(xiàn)在指向的只不過(guò)是與Test對(duì)象相同大小的一段空間,還不能算是一個(gè)對(duì)象,因?yàn)闃?gòu)造函數(shù)沒(méi)有執(zhí)行 Test* pt = (Test*)malloc(sizeof(Test)); //定位new new(pt) Test; // 注意:如果Test類的構(gòu)造函數(shù)有參數(shù)時(shí),此處需要傳參 return 0; }
內(nèi)存泄露
內(nèi)存泄露的含義:
內(nèi)存泄漏指因?yàn)槭韬龌蝈e(cuò)誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存的情況。內(nèi)存泄漏并不是指內(nèi)存在物理上的消失,而是應(yīng)用程序分配某段內(nèi)存后,因?yàn)樵O(shè)計(jì)錯(cuò)誤,失去了對(duì)該段內(nèi)存的控制,因而造成了內(nèi)存的浪費(fèi)。
內(nèi)存泄露的兩大分類:
1.堆內(nèi)存泄露(Heap leak)
堆內(nèi)存指的是程序執(zhí)行中依據(jù)須要分配通過(guò)malloc / calloc / realloc / new等從堆中分配的一塊內(nèi)存,用完后必須通過(guò)調(diào)用相應(yīng)的 free或delete 刪掉。假設(shè)程序的設(shè)計(jì)錯(cuò)誤導(dǎo)致這部分內(nèi)存沒(méi)有被釋放,那么以后這部分空間將無(wú)法再被使用,就會(huì)產(chǎn)生Heap Leak。
2.系統(tǒng)資源泄露
指程序使用系統(tǒng)分配的資源,比方套接字、文件描述符、管道等沒(méi)有使用對(duì)應(yīng)的函數(shù)釋放掉,導(dǎo)致系統(tǒng)資源的浪費(fèi),嚴(yán)重可導(dǎo)致系統(tǒng)效能減少,系統(tǒng)執(zhí)行不穩(wěn)定。
內(nèi)存泄露的危害:
在平時(shí)寫一些小測(cè)試的時(shí)候,并沒(méi)有覺(jué)得內(nèi)存泄露的危害特別大,但是在長(zhǎng)期運(yùn)行的程序中出現(xiàn)內(nèi)存泄漏,影響非常的大,出現(xiàn)內(nèi)存泄露可能會(huì)導(dǎo)致響應(yīng)越來(lái)越慢,最終出現(xiàn)卡死的現(xiàn)象。
內(nèi)存泄露的解決方案分兩種:
1.事先預(yù)防 。
2. 事后查錯(cuò)
如何事先預(yù)防?
1.養(yǎng)成良好的編碼習(xí)慣,申請(qǐng)了內(nèi)存要記得釋放。
2.采用RAII思想或者智能指針來(lái)管理資源。
3.規(guī)范使用內(nèi)部實(shí)現(xiàn)的私有內(nèi)存管理庫(kù)。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
- 超詳細(xì)分析C語(yǔ)言動(dòng)態(tài)內(nèi)存管理問(wèn)題
- C語(yǔ)言?超詳細(xì)梳理總結(jié)動(dòng)態(tài)內(nèi)存管理
- C語(yǔ)言?動(dòng)態(tài)內(nèi)存管理全面解析
- C語(yǔ)言的動(dòng)態(tài)內(nèi)存管理的深入了解
- 關(guān)于C語(yǔ)言動(dòng)態(tài)內(nèi)存管理介紹
- C語(yǔ)言動(dòng)態(tài)內(nèi)存管理介紹
- C語(yǔ)言動(dòng)態(tài)內(nèi)存管理分析總結(jié)
- C語(yǔ)言深入細(xì)致講解動(dòng)態(tài)內(nèi)存管理
相關(guān)文章
C++實(shí)現(xiàn)簡(jiǎn)單學(xué)生信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)簡(jiǎn)單學(xué)生信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03C語(yǔ)言復(fù)數(shù)的加減及輸出結(jié)構(gòu)體
大家好,本篇文章主要講的是C語(yǔ)言復(fù)數(shù)的加減及輸出結(jié)構(gòu)體,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下2022-02-02C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)線性表教程示例詳解
這篇文章主要為大家介紹了C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)線性表的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-02-02數(shù)據(jù)結(jié)構(gòu) 雙機(jī)調(diào)度問(wèn)題的實(shí)例詳解
這篇文章主要介紹了數(shù)據(jù)結(jié)構(gòu) 雙機(jī)調(diào)度問(wèn)題的實(shí)例詳解的相關(guān)資料,雙機(jī)調(diào)度問(wèn)題,又稱獨(dú)立任務(wù)最優(yōu)調(diào)度:用兩臺(tái)處理機(jī)A和B處理n個(gè)作業(yè)的實(shí)例,需要的朋友可以參考下2017-08-08C++詳細(xì)講解圖論的基礎(chǔ)與圖的儲(chǔ)存
圖論〔Graph?Theory〕是數(shù)學(xué)的一個(gè)分支。它以圖為研究對(duì)象。圖論中的圖是由若干給定的點(diǎn)及連接兩點(diǎn)的線所構(gòu)成的圖形,這種圖形通常用來(lái)描述某些事物之間的某種特定關(guān)系,用點(diǎn)代表事物,用連接兩點(diǎn)的線表示相應(yīng)兩個(gè)事物間具有這種關(guān)系2022-05-05C語(yǔ)言圍圈報(bào)數(shù)題目代碼實(shí)現(xiàn)
大家好,本篇文章主要講的是C語(yǔ)言圍圈報(bào)數(shù)題目代碼實(shí)現(xiàn),感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2022-01-01