亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C++ 內(nèi)存管理原理分析

 更新時間:2021年11月19日 17:06:36   作者:林慢慢腦瓜子嗡嗡的  
本章主要介紹C++的內(nèi)存管理,以C++的內(nèi)存分布作為引入,介紹C++不同于C語言的內(nèi)存管理方式(new delete對比 malloc free),最后為了加深讀者的理解,會介紹new和delete的底層實現(xiàn)原理

1.C/C++中程序內(nèi)存分布

C/C++中程序內(nèi)存區(qū)域大致劃分為:內(nèi)核空間(這部分用戶不能讀寫)、棧、內(nèi)存映射段、堆、數(shù)據(jù)段(存儲全局?jǐn)?shù)據(jù)、靜態(tài)數(shù)據(jù))、代碼段(存儲可執(zhí)行代碼、只讀常量,又稱常量區(qū))。

1.1 內(nèi)存分布圖

image-20211118094900676

1.2 小試牛刀

接下來看下如下代碼,思考下每一個變量分別在哪個內(nèi)存區(qū)域?

int globalVar = 1;
static int staticGlobalVar = 1;
void test()
{
	static int staticVar = 1;
	int localVar = 1;

	int num1[10] = { 1,2,3,4 };
	char char2[] = "abcd";
	char *pchar3 = "abcd";//有的編譯器會報錯,需要用const char 
	int* ptr1 = (int*)malloc(sizeof(int) * 4);
	int* ptr2 = (int*)calloc(4,sizeof(int));
	int* ptr3 = (int*)realloc(ptr2,sizeof(int) * 4);
	free(ptr1);
	free(ptr2);
}

上述代碼段對應(yīng)變量區(qū)域劃分如下:

image-20211118095816959

2.C語言部分的動態(tài)內(nèi)存管理方式

再來回顧一下之前C語言部分的動態(tài)內(nèi)存管理方式:malloc / calloc/ realloc和free

帶著兩個問題閱讀下述程序段:

1.malloc / calloc/ realloc的區(qū)別是什么?

2.最后需要free(p2)嗎?

void Test()
{
	int* p1 = (int*)malloc(sizeof(int));
	free(p1);

	int* p2 = (int*)calloc(4, sizeof(int));
	int* p3 = (int*)realloc(p2, sizeof(int) * 10);

	free(p3);
}

答:

1.calloc相當(dāng)于malloc+memset(0),即開空間+初始化。

2.realloc是對malloc/calloc的空間進(jìn)行擴(kuò)容,擴(kuò)容之下又涉及到了咱們前面所講的原地擴(kuò)容和異地擴(kuò)容倆種情景:原地擴(kuò)容p2和p3是一樣的,也有可能是異地擴(kuò)容,那么p2指向的空間已經(jīng)被釋放了,所以兩種情況下我們都可以不需要處理p2。

image-20211118101324827

3.C++內(nèi)存管理方式

總之就是C語言那套內(nèi)存管理方式相對麻煩,所以C++提出了自己的內(nèi)存管理方式:通過new和delete操作符進(jìn)行動態(tài)內(nèi)存管理.

3.1new/delete操作內(nèi)置類型

1.開辟單個元素

開辟單個元素基本語法: type * ptr = new type(content); ,可以理解成動態(tài)申請一個type類型的空間并將其中內(nèi)容初始化為content,當(dāng)然,你也可以選擇不初始化。

釋放空間語法: delete name;

例:

int* a = new int(100);  //動態(tài)申請一個int類型的空間并初始化為100
delete a;

2.開辟n個type類型的空間

開辟n個type類型基本語法: type* name = new type[n]

刪除的基本語法:delete[] name;

例:

int* ptr = new int[100];//動態(tài)申請100個int類型的空間
delete[] ptr;           //注意哦!一定要匹配哦!不然必崩潰!

3.對于內(nèi)置類型,malloc/free和new/delete確實沒有什么區(qū)別,二者的作用完全一樣。

例:

int main()
{
	//malloc向內(nèi)存申請4個整型大小的空間
	int* p1 = (int*)malloc(sizeof(int) * 4);
	//new向內(nèi)存申請4個整型大小的空間
	int* p2 = new int[4];
	//free釋放掉p1申請的空間
	free(p1);
	p1 = nullptr;
	//delete釋放掉p2申請的空間
	delete[] p2;
	return 0;
}

image-20211118103800232

3.2 new/delete操作自定義類型

class  Date
{
public:
	Date(int year=2021, int month=1, int day=1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};


int main()
{
	//malloc申請十個Date空間
	Date* p1 = (Date*)malloc(sizeof(Date) * 10);
	free(p1);

	//new申請十個Date空間
	Date* p2 = new Date[10];
	delete[] p2;

	return 0;
}

區(qū)別:在申請自定義類型空間的時候,new會調(diào)用構(gòu)造函數(shù),delete會調(diào)用析構(gòu)函數(shù),而mallo和free不會哦!

4.new和delete底層實現(xiàn)原理(important!!!)

image-20211118121205737

在講解他們的底層實現(xiàn)原理之前需要先先介紹一下兩個全局函數(shù),分別是operator newoperator delete.

new和delete是用戶進(jìn)行動態(tài)內(nèi)存申請和釋放的操作符,operator new和operator delete是系統(tǒng)提供的全局函數(shù),new在底層調(diào)用operator new全局函數(shù)來申請空間,delete在底層通過調(diào)用operator delete全局函數(shù)來釋放空間。

4.1operator new/operator delete

operator new封裝了 malloc 和失敗拋異常倆個部分,

下面是operator new的代碼:

void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
	// try to allocate size bytes
	void* p;
	while ((p = malloc(size)) == 0)              //如果開辟成功就不會進(jìn)入循環(huán),并且可以清晰
		if (_callnewh(size) == 0)
		{
			// report no memory
			// 如果申請內(nèi)存失敗了,這里會拋出bad_alloc 類型異常
			static const std::bad_alloc nomem;
			_RAISE(nomem);
		}
	return (p);
}

類似的,operator delete封裝了free

下面是operator delete的代碼:

void operator delete(void* pUserData)
{
	_CrtMemBlockHeader* pHead;
	RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
	if (pUserData == NULL)
		return;
	_mlock(_HEAP_LOCK); /* block other threads */
	__TRY
		/* get a pointer to memory block header */
		pHead = pHdr(pUserData);
	/* verify block type */
	_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
	_free_dbg(pUserData, pHead->nBlockUse);
	__FINALLY
		_munlock(_HEAP_LOCK); /* release other threads */
	__END_TRY_FINALLY
		return;
}

總結(jié):通過觀察上述倆個全局函數(shù)的實現(xiàn),不難發(fā)現(xiàn)operator new實際也是通過malloc來申請空間,如果malloc申請空間成功就直接返回,否則執(zhí)行用戶提供的空間不足應(yīng)對措施,如果用戶提供該措施就繼續(xù)申請,否則就拋異常,operator delete最終是通過free來釋放空間的。

4.2new和delete的實現(xiàn)原理

內(nèi)置類型

malloc/free與new/delete在處理內(nèi)置類型時并沒有區(qū)別,只是malloc申請空間失敗時返回空指針,而new申請空間時是拋異常,new/delete申請和釋放的是單個元素的空間,new[]和delete[]申請的是連續(xù)空間。

自定義類型

1.new的原理:1.調(diào)用operator new函數(shù)申請空間。2.在申請空間上執(zhí)行構(gòu)造函數(shù),完成對象的初始化。

2.delete的原理:1.在空間上執(zhí)行析構(gòu)函數(shù),完成對象中資源的清理工作。2.調(diào)用operator delete函數(shù)釋放空間。

另外new T[N]的原理:調(diào)用operator new[]函數(shù),在operator new[]中實際調(diào)用N次operator new函數(shù)完成N個對象空間的申請,然后在申請的空間上執(zhí)行N次構(gòu)造函數(shù)。**delete[]的原理:**在釋放的對象空間上執(zhí)行N次析構(gòu)函數(shù),完成N個對象中資源的清理。然后調(diào)用operator delete[]釋放空間,實際在operator delete[]中調(diào)用N次operator delete來釋放空間。

初學(xué)者看到“delete調(diào)用析構(gòu)函數(shù),完成對象資源的清理工作,后邊又調(diào)用operator delete函數(shù)釋放空間”這部分內(nèi)容時可能會比較混亂,這里以棧為例子詳細(xì)說下:

struct Stack
{
	int* _a;
	int _top;
	int _capacity;
	Stack(int capacity = 4)
		:_a(new int[capacity])
		,_size(0)
		,_capacity(capacity)
	{
		cout << "Stack(int capacity = 4)" << endl;
	}
	~Stack()
	{
		delete _a;
		_top = _capacity = 0;
		cout << "~Stack()" << endl;
	}
};

int main()
{
	Stack st;

	Stack* ps = new Stack;
	delete ps;
	return 0;
}

image-20211118143509751

首先,創(chuàng)建st變量,存放在棧當(dāng)中,然后調(diào)用構(gòu)造函數(shù)_a申請空間(對應(yīng)上圖動作1)。

接著,對于ps,會先去堆上調(diào)用operator new開辟一塊空間(對應(yīng)上圖動作2),再調(diào)用構(gòu)造函數(shù)對對象進(jìn)行初始化,初始化時_a又會申請空間(對應(yīng)上圖動作3)

最后,delete[] ps,會先調(diào)用析構(gòu)函數(shù)完成對象資源的清理,即釋放_ a申請的空間,然后調(diào)用operator delete釋放ps申請的空間,然后調(diào)用析構(gòu)函數(shù) _ a申請的空間。(就是步驟321)

5.相關(guān)面經(jīng)

5.1malloc/free與new/delete的區(qū)別

1.malloc/free是函數(shù),而new/delete是操作符。

2.malloc申請的空間不會初始化,而new申請的空間可以初始化(內(nèi)置類型new也不會初始化)。

3.malloc申請空間時需要手動計算要申請的空間的字節(jié)數(shù),而new申請空間只需要所申請的類型即可。

4.malloc的返回值為void*,使用是需要強(qiáng)制類型轉(zhuǎn)換,而new不需要,因為new跟的是空間的類型。

5.對于申請內(nèi)存失敗,malloc的處理是返回空指針NULL,而new的處理是拋異常

6.對于自定義類型,new/delete會調(diào)用其構(gòu)造/析構(gòu)函數(shù),而malloc/delete不會。

5.2什么是內(nèi)存泄漏?

內(nèi)存泄漏指因為疏忽或錯誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存的情況。內(nèi)存泄漏并不是指內(nèi)存在物理上的消失,而是應(yīng)用程序分配某段內(nèi)存后,因為設(shè)計錯誤,失去了對該段內(nèi)存的控制,因而造成了內(nèi)存的浪費(fèi)。

image-20211118150110386

5.3內(nèi)存泄漏的危害

如果是長期運(yùn)行的程序出現(xiàn)內(nèi)存泄漏,影響很大,如操作系統(tǒng)、后臺服務(wù)等等,出現(xiàn)內(nèi)存泄漏會導(dǎo)致響應(yīng)越來越慢,最終卡死。

比如王者榮耀后臺服務(wù),長期運(yùn)行,只有升級的時候才會停,內(nèi)存泄漏會導(dǎo)致可用內(nèi)存越來越少,程序越來越慢,甚至掛掉。

再比如物聯(lián)網(wǎng)設(shè)備:各種智能家居、智能機(jī)器人等等,它們內(nèi)存很小,也經(jīng)不起內(nèi)存泄漏的折騰。

by the way,對于C++我們需要主動釋放內(nèi)存,但是在Java當(dāng)中,不再需要主動釋放內(nèi)存,Java后臺有垃圾回收器,接管了內(nèi)存釋放(所以Java寫得好舒服,嗚嗚嗚)

5.4如何預(yù)防內(nèi)存泄漏(先了解一下,后續(xù)作者再詳細(xì)介紹)

1.智能指針

2.內(nèi)存泄漏檢測工具

2.1在linux環(huán)境下:

image-20211114145524213

2.2在Windows環(huán)境下使用第三方工具:VLD工具

img

原理:以Visual Leak Detector為例,其工作分為3步,首先在初始化注冊一個鉤子函數(shù);然后在內(nèi)存分配時該鉤子函數(shù)被調(diào)用以記錄下當(dāng)時的現(xiàn)場;最后檢查堆內(nèi)存分配鏈表以確定是否存在內(nèi)存泄漏并將泄漏內(nèi)存的現(xiàn)場轉(zhuǎn)換成可讀的形式輸出。

感謝您的閱讀?。?!如果內(nèi)容對你有幫助的話,記得給我三連(點贊、收藏、關(guān)注)——做個手有余香的人。

到此這篇關(guān)于C++ 內(nèi)存管理原理分析的文章就介紹到這了,更多相關(guān)C++ 內(nèi)存管理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言實現(xiàn)訪問及查詢MySQL數(shù)據(jù)庫的方法

    C語言實現(xiàn)訪問及查詢MySQL數(shù)據(jù)庫的方法

    這篇文章主要介紹了C語言實現(xiàn)訪問及查詢MySQL數(shù)據(jù)庫的方法,涉及C語言基于libmysql.lib實現(xiàn)訪問MySQL數(shù)據(jù)庫的相關(guān)操作技巧,需要的朋友可以參考下
    2018-01-01
  • C++實現(xiàn)下載的代碼

    C++實現(xiàn)下載的代碼

    這篇文章主要介紹了C++實現(xiàn)下載的代碼,以下載百度圖片為例較為完整的講述了C++下載的具體實現(xiàn)方法,需要的朋友可以參考下
    2014-10-10
  • C語言數(shù)據(jù)結(jié)構(gòu)實現(xiàn)字符串分割的實例

    C語言數(shù)據(jù)結(jié)構(gòu)實現(xiàn)字符串分割的實例

    這篇文章主要介紹了C語言數(shù)據(jù)結(jié)構(gòu)實現(xiàn)字符串分割的實例的相關(guān)資料,希望通過本文能幫助到大家實現(xiàn)這樣的功能,需要的朋友可以參考下
    2017-10-10
  • C++無法打開源文件bits/stdc++.h的問題

    C++無法打開源文件bits/stdc++.h的問題

    這篇文章主要介紹了C++無法打開源文件bits/stdc++.h的問題以及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • C++線程中幾類鎖的詳解

    C++線程中幾類鎖的詳解

    這篇文章主要為大家介紹了C++線程中幾類鎖,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-11-11
  • C++實現(xiàn)中綴表達(dá)式轉(zhuǎn)化為后綴表達(dá)式詳解

    C++實現(xiàn)中綴表達(dá)式轉(zhuǎn)化為后綴表達(dá)式詳解

    這篇文章主要為大家詳細(xì)介紹了如何利用C++解決實現(xiàn)中綴表達(dá)式轉(zhuǎn)換為后綴表達(dá)式的問題,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C語言學(xué)習(xí)之標(biāo)識符的使用詳解

    C語言學(xué)習(xí)之標(biāo)識符的使用詳解

    C語言標(biāo)識符是用于表示變量、函數(shù)、常量、類型等程序元素的名稱,這篇文章將通過一些簡單的示例為大家介紹一下C語言標(biāo)識符的使用,需要的可以參考一下
    2023-05-05
  • C++實現(xiàn)簡易計算器功能

    C++實現(xiàn)簡易計算器功能

    這篇文章主要為大家詳細(xì)介紹了C++實現(xiàn)簡易計算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C++實現(xiàn)迷宮游戲

    C++實現(xiàn)迷宮游戲

    這篇文章主要為大家詳細(xì)介紹了C++實現(xiàn)迷宮游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • 詳解C語言常用的一些轉(zhuǎn)換工具函數(shù)

    詳解C語言常用的一些轉(zhuǎn)換工具函數(shù)

    這篇文章主要介紹了C語言常用的一些轉(zhuǎn)換工具函數(shù),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11

最新評論