C++圖文并茂分析講解內(nèi)存管理
1.了解一些基本的內(nèi)存段(圖演示)
驗(yàn)證棧是向下生長(zhǎng)的
#include<iostream> using namespace std; int main() { int a = 3; int b = 4; int c = 5; int d = 6; cout <<"a:"<< &a << endl; cout << "b:"<<&b << endl; cout << "c:"<<&c << endl; cout << "d:"<<&d << endl; return 0; }
驗(yàn)證堆一般是向上生長(zhǎng)的(不一定)
#include<iostream> using namespace std; int main() { int num = 10; while (num--) { int *p1 = (int*)malloc(sizeof(int)); int *p2 = (int*)malloc(sizeof(int)); cout <<"p1"<< p1 << endl; cout <<"p2"<<p2 << endl; cout << endl; free(p1); } return 0; }
一般情況下,p1
的地址是比p2
的地址高的(因?yàn)槎岩话闶窍蛏仙L(zhǎng)的),但是有時(shí)候是不一定的。
鞏固內(nèi)存管理知識(shí)點(diǎn)
答案
溫馨提示:題目中的指針是局部指針變量,是在棧上的,但是它指向的內(nèi)容(解引用)可能是堆區(qū)或者常量區(qū)的。,可以畫(huà)畫(huà)圖理解理解
2.c++申請(qǐng)動(dòng)態(tài)內(nèi)存的新玩兒法new,delete
回顧c語(yǔ)言動(dòng)態(tài)內(nèi)存管理的方式
malloc
和calloc
和realloc
malloc
堆上動(dòng)態(tài)開(kāi)空間calloc
堆上動(dòng)態(tài)開(kāi)空間+初始化成0等價(jià)于malloc
+memset
realloc
指針已有的空間擴(kuò)容
原題增容–后面又足夠的空間
異地增容–后面沒(méi)有足夠的空間
開(kāi)辟內(nèi)置類型的空間
//C++開(kāi)辟動(dòng)態(tài)內(nèi)存的新玩法 //語(yǔ)法演示: #include<iostream> using namespace std; int main() { //申請(qǐng)一個(gè)int的動(dòng)態(tài)空間 int* p1 = (int*)malloc(sizeof(int)); *p1 = 1; int* p2 = new int(2);//這里是初始化 free(p1); delete p2; //申請(qǐng)一個(gè)10各int的動(dòng)態(tài)數(shù)組 int *p3 = (int*)malloc(sizeof(int)* 10); for (int i = 0; i < 10; i++) { p3[i] = i + 1; } int *p4 = new int[10]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};//初始化 free(p3); delete[]p4; return 0; }
跟c語(yǔ)言的版本相比,c++的版本,初始化時(shí)顯得比較方便,而且語(yǔ)法比較簡(jiǎn)潔。當(dāng)然了,更大的優(yōu)越性還在后面。
開(kāi)辟自定義類型的空間(請(qǐng)用vs2013以上版本測(cè)試代碼)
#include<iostream> using namespace std; struct ListNode { int _val; ListNode* _next; ListNode* _prev; //構(gòu)造函數(shù) ListNode(int val = 0) :_val(val) , _next(nullptr) , _prev(nullptr) { cout<<"ListNode(int val = 0)"<<endl; } ~ListNode() { cout << "ListNode()" << endl; } }; int main() { //申請(qǐng)一個(gè)結(jié)點(diǎn)的空間 ListNode* pa = (ListNode*)malloc(sizeof(ListNode)*4); ListNode* pb = new ListNode(1);//不用去用sizeof去計(jì)算空間大小,很方便 free(pa); delete pb; //申請(qǐng)4個(gè)結(jié)點(diǎn)的空間--當(dāng)然了一般不會(huì)這么玩兒,我們只是看看效果 ListNode* pc = (ListNode*)malloc(sizeof(ListNode)* 4); ListNode* pd = new ListNode[4]{1, 2, 3, 4}; free(pc); delete[]pd; return 0; }
? 學(xué)過(guò)c語(yǔ)言版本的數(shù)據(jù)結(jié)構(gòu)的小伙伴都知道,我們push_back一個(gè)結(jié)點(diǎn)時(shí),需要先實(shí)現(xiàn)一個(gè)buynewnode
的函數(shù)(創(chuàng)建一個(gè)結(jié)點(diǎn),并且對(duì)其進(jìn)行初始化)。而new這個(gè)操作符,在創(chuàng)建結(jié)點(diǎn)的同時(shí),已經(jīng)幫我們實(shí)現(xiàn)了結(jié)點(diǎn)的初始化。調(diào)用了構(gòu)造函數(shù),而且delete
還調(diào)用了析構(gòu)函數(shù)。
總結(jié)一下
- c++中,如果是申請(qǐng)內(nèi)置類型對(duì)象或者數(shù)組,
malloc
和new
沒(méi)有太大區(qū)別 - 如果時(shí)自定義類型,區(qū)別很大,new和delete時(shí)開(kāi)空間+初始化,析構(gòu)清理+釋放空間,
malloc
和free
僅僅時(shí)開(kāi)空間+釋放空間 - 建議在c++中,無(wú)論時(shí)內(nèi)置類型還是自定義類型的申請(qǐng)釋放,盡量使用new和delete。
3. 32位平臺(tái)下可以開(kāi)辟多大的內(nèi)存
我:cpu過(guò)來(lái)遭罪
cpu:你不要過(guò)來(lái)啊
上述程序,我們開(kāi)了1.8 G左右的內(nèi)存,加上需要堆上的小內(nèi)存,最后的綜合有2 G的空間
如何開(kāi)辟4G的內(nèi)存
將項(xiàng)目屬性修改一下,改成64位平臺(tái)即可,64位平臺(tái)有2^34 G的空間(虛擬內(nèi)存)在這我們不做細(xì)說(shuō),因?yàn)槲乙膊惶私釲inux。
4.了解operator new和operator delete
new
其實(shí)是operator new
+ 構(gòu)造函數(shù)
delete
其實(shí)是operator delete
+構(gòu)造函數(shù)
new
和delete
是用戶進(jìn)行動(dòng)態(tài)內(nèi)存申請(qǐng)和釋放的操作符,operator new
和operator delete
是系統(tǒng)提供的全局函數(shù),new在底層調(diào)用operator new全局函數(shù)來(lái)申請(qǐng)空間,delete在底層通過(guò)operator delete全局函數(shù)來(lái)釋放空間
大家可以將operator new和operator delete理解成和malloc
和free一樣用法的函數(shù)。
唯一不同的地方是,operator new和malloc
開(kāi)辟空間失敗的處理方式不一樣,malloc
是返回NULL空指針,而operator是拋異常,下面代碼讓大家看看效果,不必深究,以后會(huì)有介紹。
struct ListNode { int _val; ListNode* _next; ListNode* _prev; //構(gòu)造函數(shù) ListNode(int val = 0) :_val(val) , _next(nullptr) , _prev(nullptr) { cout << "ListNode(int val = 0)" << endl; } ~ListNode() { cout << "ListNode()" << endl; } }; void f() { // 他的用法跟malloc和free是完全一樣的,功能都是在堆上申請(qǐng)釋放空間 // 失敗了處理方式不一樣,malloc失敗返回NULL,operator new失敗以后拋異常 ListNode* p1 = (ListNode*)malloc(sizeof(ListNode)); free(p1); ListNode* p2 = (ListNode*)operator new(sizeof(ListNode)); operator delete(p2); void* p3 = malloc(0x7fffffff); if (p3 == NULL) { cout << "malloc fail" << endl; } void* p4 = operator new(0x7fffffff); ListNode* p5 = new ListNode(2); cout << "繼續(xù)" << endl; } // // int main() { try { f(); } catch (exception& e) { cout << e.what() << endl; } return 0; }
malloc
失敗返回NULL,程序還會(huì)繼續(xù)向下執(zhí)行,但是operator new失敗,就會(huì)報(bào)異常,f函數(shù)后面的沒(méi)有在繼續(xù)執(zhí)行,然后走進(jìn)catch語(yǔ)句中。
5.operator new和operator delete的類函數(shù)重載
struct ListNode//目的是提高效率 { ListNode* _next; ListNode* _prev; int _val; // 類中重載專屬operator new 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); cout << "memory pool deallocate" << endl; } ListNode(int val) :_next(nullptr) , _prev(nullptr) , _val(val) {} }; int main() { ListNode* p = new ListNode(1); delete p; return 0; }
如果你自己在類里面寫(xiě)了operator new
和operator delete
,那么編譯器就不會(huì)去調(diào)用系統(tǒng)提供的了,這是一種提高效率的方式。
我們是可以通過(guò)反匯編來(lái)看效果的
6.定位new–placement-new
通過(guò)上述的學(xué)習(xí)我們知道,malloc
,和operator
是不會(huì)去調(diào)用構(gòu)造函數(shù)的,new
會(huì)去調(diào)用構(gòu)造函數(shù),而且構(gòu)造函數(shù)是只允許構(gòu)造出對(duì)象時(shí)調(diào)用,而你的對(duì)象創(chuàng)建出來(lái)之后是無(wú)法調(diào)用構(gòu)造的。
但是如果我們operator new
了一塊空間(未初始化),但是又想要調(diào)用其構(gòu)造函數(shù),該怎們辦呢?
class A { public: A(int a = 0) :_a(a) { cout << "A(int a = 0)" << endl; } ~A() { cout << "~A()" << endl; } private: int _a; }; int main() { A* pa = (A*)operator new(sizeof(A)); //pa->A();//error錯(cuò)誤調(diào)用方式,構(gòu)造函數(shù)只允許構(gòu)造時(shí)進(jìn)行調(diào)用 new(pa)A; // 定位new,placement-new,顯示調(diào)用構(gòu)造函數(shù)初始化這塊對(duì)象空間 A* pb = (A*)operator new(sizeof(A)); new(pb)A(3); A* pc = new A; new(pc)A(3); // 等于 delete p pa->~A(); // 析構(gòu)函數(shù)可以顯示調(diào)用 operator delete(pa); pb->~A(); operator delete(pb); delete pc; return 0; }
大家要知道定位new哦,他是一種對(duì)已經(jīng)創(chuàng)建出來(lái)的對(duì)象,還能繼續(xù)調(diào)用其構(gòu)造函數(shù)的方式。
7.`malloc`/`free`和`new`/`delete`的區(qū)別
??济嬖囶}
8.再次理解內(nèi)存泄漏
首先大家先想一想這個(gè)問(wèn)題:內(nèi)存泄漏是指針丟了還是內(nèi)存丟了?
內(nèi)存管理中,內(nèi)存是用指針去維護(hù)的,當(dāng)你的動(dòng)態(tài)內(nèi)存空間還沒(méi)有釋放時(shí),你已經(jīng)把指針弄丟了,那么你將無(wú)法控制這段空間,進(jìn)而導(dǎo)致內(nèi)存泄漏。
什么是內(nèi)存泄漏,內(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)存泄漏的危害:長(zhǎng)期運(yùn)行的程序出現(xiàn)內(nèi)存泄漏,影響很大,如操作系統(tǒng)、后臺(tái)服務(wù)等等,出現(xiàn)內(nèi)存泄漏會(huì) 導(dǎo)致響應(yīng)越來(lái)越慢,最終卡死。
到此這篇關(guān)于C++圖文并茂分析講解內(nèi)存管理的文章就介紹到這了,更多相關(guān)C++內(nèi)存管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C++ 多態(tài)性虛函數(shù)和動(dòng)態(tài)綁定學(xué)習(xí)筆記
- 關(guān)于C++虛函數(shù)與靜態(tài)、動(dòng)態(tài)綁定的問(wèn)題
- C++實(shí)現(xiàn)動(dòng)態(tài)綁定代碼分享
- 深入理解C++的動(dòng)態(tài)綁定與靜態(tài)綁定的應(yīng)用詳解
- 詳解C++動(dòng)態(tài)內(nèi)存管理
- C++內(nèi)存管理面經(jīng)
- 詳解C++中動(dòng)態(tài)內(nèi)存管理和泛型編程
- 一文詳解C++中動(dòng)態(tài)內(nèi)存管理
- C語(yǔ)言與C++中內(nèi)存管理詳解
- 一起來(lái)學(xué)習(xí)C++的動(dòng)態(tài)內(nèi)存管理
- C++中動(dòng)態(tài)綁定和內(nèi)存管理的實(shí)現(xiàn)
相關(guān)文章
C語(yǔ)言 數(shù)據(jù)結(jié)構(gòu)雙向鏈表簡(jiǎn)單實(shí)例
這篇文章主要介紹了C語(yǔ)言 數(shù)據(jù)結(jié)構(gòu)雙向鏈表簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-03-03vs2019安裝及簡(jiǎn)單處理技巧(超詳細(xì))
這篇文章主要介紹了vs2019安裝及簡(jiǎn)單處理方法,本文是一篇非常詳細(xì)的教程,通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06C 程序?qū)崿F(xiàn)密碼隱秘輸入的實(shí)例 linux系統(tǒng)可執(zhí)行
下面小編就為大家?guī)?lái)一篇C 程序?qū)崿F(xiàn)密碼隱秘輸入的實(shí)例 linux系統(tǒng)可執(zhí)行。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11GCC 編譯使用動(dòng)態(tài)鏈接庫(kù)和靜態(tài)鏈接庫(kù)的方法
根據(jù)鏈接時(shí)期的不同,庫(kù)又有靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)之分,有別于靜態(tài)庫(kù),動(dòng)態(tài)庫(kù)的鏈接是在程序執(zhí)行的時(shí)候被鏈接的2013-03-03C++分步實(shí)現(xiàn)職工管理系統(tǒng)詳解
這篇文章主要為大家詳細(xì)介紹了基于C++實(shí)現(xiàn)職工管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-10-10C語(yǔ)言中的結(jié)構(gòu)體的入門(mén)學(xué)習(xí)教程
這篇文章主要介紹了C語(yǔ)言中的結(jié)構(gòu)體的入門(mén)學(xué)習(xí)教程,以struct語(yǔ)句定義的結(jié)構(gòu)體是C語(yǔ)言編程中的重要基礎(chǔ),需要的朋友可以參考下2015-12-12C++ 先對(duì)數(shù)組排序,在進(jìn)行折半查找
以下小編就為大家介紹兩種實(shí)現(xiàn)方法。第一種方法是,選擇排序法+循環(huán)折半查找法。第二種方法是,冒泡排序法+遞歸折半查找法。需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2013-10-10