C++圖文并茂分析講解內(nèi)存管理
1.了解一些基本的內(nèi)存段(圖演示)

驗(yàn)證棧是向下生長的
#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)證堆一般是向上生長的(不一定)

#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的),但是有時候是不一定的。

鞏固內(nèi)存管理知識點(diǎn)

答案

溫馨提示:題目中的指針是局部指針變量,是在棧上的,但是它指向的內(nèi)容(解引用)可能是堆區(qū)或者常量區(qū)的。,可以畫畫圖理解理解

2.c++申請動態(tài)內(nèi)存的新玩兒法new,delete
回顧c語言動態(tài)內(nèi)存管理的方式
malloc和calloc和realloc
malloc堆上動態(tài)開空間calloc堆上動態(tài)開空間+初始化成0等價于malloc+memsetrealloc指針已有的空間擴(kuò)容
原題增容–后面又足夠的空間
異地增容–后面沒有足夠的空間
開辟內(nèi)置類型的空間
//C++開辟動態(tài)內(nèi)存的新玩法
//語法演示:
#include<iostream>
using namespace std;
int main()
{
//申請一個int的動態(tài)空間
int* p1 = (int*)malloc(sizeof(int));
*p1 = 1;
int* p2 = new int(2);//這里是初始化
free(p1);
delete p2;
//申請一個10各int的動態(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語言的版本相比,c++的版本,初始化時顯得比較方便,而且語法比較簡潔。當(dāng)然了,更大的優(yōu)越性還在后面。
開辟自定義類型的空間(請用vs2013以上版本測試代碼)
#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()
{
//申請一個結(jié)點(diǎn)的空間
ListNode* pa = (ListNode*)malloc(sizeof(ListNode)*4);
ListNode* pb = new ListNode(1);//不用去用sizeof去計(jì)算空間大小,很方便
free(pa);
delete pb;
//申請4個結(jié)點(diǎn)的空間--當(dāng)然了一般不會這么玩兒,我們只是看看效果
ListNode* pc = (ListNode*)malloc(sizeof(ListNode)* 4);
ListNode* pd = new ListNode[4]{1, 2, 3, 4};
free(pc);
delete[]pd;
return 0;
}
? 學(xué)過c語言版本的數(shù)據(jù)結(jié)構(gòu)的小伙伴都知道,我們push_back一個結(jié)點(diǎn)時,需要先實(shí)現(xiàn)一個buynewnode的函數(shù)(創(chuàng)建一個結(jié)點(diǎn),并且對其進(jìn)行初始化)。而new這個操作符,在創(chuàng)建結(jié)點(diǎn)的同時,已經(jīng)幫我們實(shí)現(xiàn)了結(jié)點(diǎn)的初始化。調(diào)用了構(gòu)造函數(shù),而且delete還調(diào)用了析構(gòu)函數(shù)。
總結(jié)一下
- c++中,如果是申請內(nèi)置類型對象或者數(shù)組,
malloc和new沒有太大區(qū)別 - 如果時自定義類型,區(qū)別很大,new和delete時開空間+初始化,析構(gòu)清理+釋放空間,
malloc和free僅僅時開空間+釋放空間 - 建議在c++中,無論時內(nèi)置類型還是自定義類型的申請釋放,盡量使用new和delete。
3. 32位平臺下可以開辟多大的內(nèi)存
我:cpu過來遭罪
cpu:你不要過來啊

上述程序,我們開了1.8 G左右的內(nèi)存,加上需要堆上的小內(nèi)存,最后的綜合有2 G的空間
如何開辟4G的內(nèi)存
將項(xiàng)目屬性修改一下,改成64位平臺即可,64位平臺有2^34 G的空間(虛擬內(nèi)存)在這我們不做細(xì)說,因?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)行動態(tài)內(nèi)存申請和釋放的操作符,operator new和operator delete是系統(tǒng)提供的全局函數(shù),new在底層調(diào)用operator new全局函數(shù)來申請空間,delete在底層通過operator delete全局函數(shù)來釋放空間
大家可以將operator new和operator delete理解成和malloc 和free一樣用法的函數(shù)。
唯一不同的地方是,operator new和malloc開辟空間失敗的處理方式不一樣,malloc是返回NULL空指針,而operator是拋異常,下面代碼讓大家看看效果,不必深究,以后會有介紹。
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是完全一樣的,功能都是在堆上申請釋放空間
// 失敗了處理方式不一樣,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,程序還會繼續(xù)向下執(zhí)行,但是operator new失敗,就會報異常,f函數(shù)后面的沒有在繼續(xù)執(zhí)行,然后走進(jìn)catch語句中。
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;
}如果你自己在類里面寫了operator new和operator delete,那么編譯器就不會去調(diào)用系統(tǒng)提供的了,這是一種提高效率的方式。
我們是可以通過反匯編來看效果的

6.定位new–placement-new
通過上述的學(xué)習(xí)我們知道,malloc,和operator是不會去調(diào)用構(gòu)造函數(shù)的,new會去調(diào)用構(gòu)造函數(shù),而且構(gòu)造函數(shù)是只允許構(gòu)造出對象時調(diào)用,而你的對象創(chuàng)建出來之后是無法調(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錯誤調(diào)用方式,構(gòu)造函數(shù)只允許構(gòu)造時進(jìn)行調(diào)用
new(pa)A; // 定位new,placement-new,顯示調(diào)用構(gòu)造函數(shù)初始化這塊對象空間
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哦,他是一種對已經(jīng)創(chuàng)建出來的對象,還能繼續(xù)調(diào)用其構(gòu)造函數(shù)的方式。
7.`malloc`/`free`和`new`/`delete`的區(qū)別
??济嬖囶}

8.再次理解內(nèi)存泄漏
首先大家先想一想這個問題:內(nèi)存泄漏是指針丟了還是內(nèi)存丟了?
內(nèi)存管理中,內(nèi)存是用指針去維護(hù)的,當(dāng)你的動態(tài)內(nèi)存空間還沒有釋放時,你已經(jīng)把指針弄丟了,那么你將無法控制這段空間,進(jìn)而導(dǎo)致內(nèi)存泄漏。
什么是內(nèi)存泄漏,內(nèi)存泄漏的危害
什么是內(nèi)存泄漏:內(nèi)存泄漏指因?yàn)槭韬龌蝈e誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存的情況。內(nèi)存泄漏并不是指內(nèi)存在物理上的消失,而是應(yīng)用程序分配某段內(nèi)存后,因?yàn)樵O(shè)計(jì)錯誤,失去了對該段內(nèi)存的控制,因而 造成了內(nèi)存的浪費(fèi)。
內(nèi)存泄漏的危害:長期運(yùn)行的程序出現(xiàn)內(nèi)存泄漏,影響很大,如操作系統(tǒng)、后臺服務(wù)等等,出現(xiàn)內(nèi)存泄漏會 導(dǎo)致響應(yīng)越來越慢,最終卡死。
到此這篇關(guān)于C++圖文并茂分析講解內(nèi)存管理的文章就介紹到這了,更多相關(guān)C++內(nèi)存管理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C++ 多態(tài)性虛函數(shù)和動態(tài)綁定學(xué)習(xí)筆記
- 關(guān)于C++虛函數(shù)與靜態(tài)、動態(tài)綁定的問題
- C++實(shí)現(xiàn)動態(tài)綁定代碼分享
- 深入理解C++的動態(tài)綁定與靜態(tài)綁定的應(yīng)用詳解
- 詳解C++動態(tài)內(nèi)存管理
- C++內(nèi)存管理面經(jīng)
- 詳解C++中動態(tài)內(nèi)存管理和泛型編程
- 一文詳解C++中動態(tài)內(nèi)存管理
- C語言與C++中內(nèi)存管理詳解
- 一起來學(xué)習(xí)C++的動態(tài)內(nèi)存管理
- C++中動態(tài)綁定和內(nèi)存管理的實(shí)現(xiàn)
相關(guān)文章
C語言 數(shù)據(jù)結(jié)構(gòu)雙向鏈表簡單實(shí)例
這篇文章主要介紹了C語言 數(shù)據(jù)結(jié)構(gòu)雙向鏈表簡單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-03-03
C 程序?qū)崿F(xiàn)密碼隱秘輸入的實(shí)例 linux系統(tǒng)可執(zhí)行
下面小編就為大家?guī)硪黄狢 程序?qū)崿F(xiàn)密碼隱秘輸入的實(shí)例 linux系統(tǒng)可執(zhí)行。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11
GCC 編譯使用動態(tài)鏈接庫和靜態(tài)鏈接庫的方法
根據(jù)鏈接時期的不同,庫又有靜態(tài)庫和動態(tài)庫之分,有別于靜態(tài)庫,動態(tài)庫的鏈接是在程序執(zhí)行的時候被鏈接的2013-03-03
C++分步實(shí)現(xiàn)職工管理系統(tǒng)詳解
這篇文章主要為大家詳細(xì)介紹了基于C++實(shí)現(xiàn)職工管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-10-10
C語言中的結(jié)構(gòu)體的入門學(xué)習(xí)教程
這篇文章主要介紹了C語言中的結(jié)構(gòu)體的入門學(xué)習(xí)教程,以struct語句定義的結(jié)構(gòu)體是C語言編程中的重要基礎(chǔ),需要的朋友可以參考下2015-12-12

