欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C/C++深入講解內(nèi)存管理

 更新時(shí)間:2022年05月31日 08:49:56   作者:風(fēng)&646  
本章主要介紹C語(yǔ)言與C++的內(nèi)存管理,以C++的內(nèi)存分布作為引入,介紹C++不同于C語(yǔ)言的內(nèi)存管理方式(new?delete對(duì)比?malloc?free),感興趣的朋友來(lái)看看吧

C/C++內(nèi)存分布

??首先我們來(lái)看一看以下代碼中變量在內(nèi)存中的存儲(chǔ)位置。

c/c++內(nèi)存分配圖:

1.棧又叫做堆棧,存儲(chǔ)非靜態(tài)局部變量/函數(shù)參數(shù)/返回值等等,棧是向下增長(zhǎng)的。

2.內(nèi)存映射段是高效的I/O映射方式,用于裝載一個(gè)共享的動(dòng)態(tài)內(nèi)存庫(kù)。用戶可使用系統(tǒng)接口創(chuàng)建共享內(nèi)存,做進(jìn)程間通信。

3.堆用于程序運(yùn)行時(shí)動(dòng)態(tài)內(nèi)存分配,堆上可以向上增長(zhǎng)的。

4.數(shù)據(jù)段 - 用于存儲(chǔ)全局?jǐn)?shù)據(jù)和靜態(tài)數(shù)據(jù)。

5.代碼段 - 可執(zhí)行的代碼/只讀常量。

C語(yǔ)言中的動(dòng)態(tài)內(nèi)存管理

malloc/calloc/realloc/free

int main()
{
	int* p1 = (int*)malloc(sizeof(int));
	int* p2 = (int*)calloc(4, sizeof(int));
	int* p3 = (int*)realloc(p2, sizeof(int) * 10);
	free(p1);
	free(p2);
	free(p3);
	return 0;
}

malloc/calloc/realloc的區(qū)別?

malloc - 堆上動(dòng)態(tài)開(kāi)辟空間

realloc - 堆上動(dòng)態(tài)開(kāi)辟空間 + 初始化為0 (相當(dāng)于malloc + memset)

calloc - 針對(duì)已經(jīng)有的空間進(jìn)行擴(kuò)容 (原地?cái)U(kuò)容或異地?cái)U(kuò)容)

C++的內(nèi)存管理

??C語(yǔ)言的內(nèi)存管理方式在c++中可以繼續(xù)使用,但是有些地方使用起來(lái)就比較麻煩了。因此c++提供了自己的內(nèi)存管理方式:通過(guò)new和delete操作符進(jìn)行動(dòng)態(tài)內(nèi)存管理。 new和delete是運(yùn)算符,不是函數(shù),因此執(zhí)行效率高。

new和delete操作內(nèi)置類(lèi)型::

int main()
{
	// new/delete和malloc/free 針對(duì)內(nèi)置類(lèi)型沒(méi)有任何差別,只是用法不同
	//動(dòng)態(tài)申請(qǐng)一個(gè)int類(lèi)型的空間
	int* p1 = new int;
	delete p1;
	//動(dòng)態(tài)申請(qǐng)一個(gè)int類(lèi)型的空間并初始化為10
	int* p2 = new int(10);
	delete p2;
	//動(dòng)態(tài)申請(qǐng)10個(gè)int類(lèi)型的空間
	int* p3 = new int[10];
	delete[] p3;
	return 0;
}

注意:申請(qǐng)和釋放單個(gè)元素的空間,使用new和delete操作符,申請(qǐng)和釋放連續(xù)的空間,使用new[]和delete[]。

new和delete操作自定義類(lèi)型::

注意: 在申請(qǐng)自定義類(lèi)型的空間時(shí),new會(huì)調(diào)用構(gòu)造函數(shù),delete會(huì)調(diào)用析構(gòu)函數(shù),而malloc和free不會(huì)。

??對(duì)于以上總結(jié)一下:

1.c++中如果是申請(qǐng)內(nèi)置類(lèi)型對(duì)象或者數(shù)組,malloc和new沒(méi)有什么區(qū)別。

2.如果是自定義類(lèi)型,那么區(qū)別很大,new和delete是開(kāi)空間 + 初始化,析構(gòu)清理 + 釋放空間,malloc和free僅僅是開(kāi)空間 + 釋放空間。

3.建議在c++中,無(wú)論是自定義類(lèi)型還是內(nèi)置類(lèi)型的申請(qǐng)和釋放,盡量使用new和delete。

operator new與operator delete函數(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在底層提供operator delete全局函數(shù)來(lái)釋放空間。

如下是c++官方對(duì)于這兩個(gè)函數(shù)的描述:

operator new和operator delete的實(shí)現(xiàn)代碼:

/*
operator new:該函數(shù)實(shí)際通過(guò)malloc來(lái)申請(qǐng)空間,當(dāng)malloc申請(qǐng)空間成功時(shí)直接返回;申請(qǐng)空間失敗,
嘗試執(zhí)行空間不足應(yīng)對(duì)措施,如果改應(yīng)對(duì)措施用戶設(shè)置了,則繼續(xù)申請(qǐng),否則拋異常。
*/
void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
	// try to allocate size bytes
	void* p;
	while ((p = malloc(size)) == 0)
		if (_callnewh(size) == 0)
		{
			// report no memory
			// 如果申請(qǐng)內(nèi)存失敗了,這里會(huì)拋出bad_alloc 類(lèi)型異常
			static const std::bad_alloc nomem;
			_RAISE(nomem);
		}
	return (p);
}
/*
operator delete: 該函數(shù)最終是通過(guò)free來(lái)釋放空間的
*/
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;
}
/*
free的實(shí)現(xiàn)
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)

通過(guò)上訴兩個(gè)全局函數(shù)的實(shí)現(xiàn)代碼可以看出,operator new實(shí)際上是通過(guò)malloc來(lái)申請(qǐng)空間的,如果malloc申請(qǐng)空間成功就直接返回,否則執(zhí)行用戶提供的空間不足的應(yīng)對(duì),如果用戶提供該措施就繼續(xù)申請(qǐng),否則就拋異常。operator delete最終是通過(guò)free來(lái)釋放空間的。

operator new的使用案例:

struct ListNode
{
	ListNode(int data = 0)
		:_next(nullptr)
		,_prev(nullptr)
		,_data(data)
	{}
	ListNode* _next;
	ListNode* _prev;
	int _data;
};
//operator new的用法跟malloc和free是一樣的,都是在堆上申請(qǐng)空間
//只是申請(qǐng)空間失敗后的處理方式不一樣,malloc失敗返回NULL,operator new失敗以后拋異常
int main()
{
	//C語(yǔ)言
	ListNode* p1 = (ListNode*)malloc(sizeof(ListNode));
	free(p1);
	//c++
	ListNode* p2 = (ListNode*)operator new(sizeof(ListNode));
	operator delete(p2);
	int* p3 = (int*)malloc(100000000000000000);
	if (p3 == NULL)
	{
		cout << "malloc fail" << endl;
	}
	try
	{
		int* p4 = (int*)operator new(100000000000000000);
	}
	//開(kāi)辟空間失敗,捕獲異常信息
	catch (exception& e)
	{
		cout << e.what() << endl;
	}
	return 0;
}

operator delete的使用案例:

class A
{
public:
	A(int a = 0)
	{
		cout << "A()" << this << endl;
	}
	~A()
	{
		cout << "~A()" << this << endl;
	}
private:
	int _a;
};
int main()
{
	//c語(yǔ)言  ->  A* p = (A*)malloc(sizeof(A));
	//等價(jià)于直接用 A* p = new A;
	A* p = (A*)operator new(sizeof(A));
	new(p)A; // new(p)A(2);  定位new,placement-new,顯示調(diào)用構(gòu)造函數(shù)初始化這塊空間對(duì)象
	//等價(jià)于 delete p
	p->~A();  //析構(gòu)函數(shù)可以顯示調(diào)用
	operator delete(p);
	return 0;
}

operator new與operator delete的類(lèi)專屬重載

內(nèi)存池:內(nèi)存池的主要作用是提高效率。通過(guò)一次性申請(qǐng)比較大的空間,來(lái)避免小空間內(nèi)存的頻繁申請(qǐng)和釋放,每次需要為對(duì)象分配內(nèi)存空間時(shí),在已經(jīng)申請(qǐng)好的大的空間內(nèi)分配??臻e區(qū)被按照對(duì)象大小劃分為若干塊,每個(gè)塊之間通過(guò)鏈表連接起來(lái)。

??以下代碼演示了,針對(duì)鏈表的節(jié)點(diǎn)ListNode通過(guò)重載類(lèi)專屬 operator new / operator delete ,實(shí)現(xiàn)鏈表節(jié)點(diǎn)使用內(nèi)存池申請(qǐng)和釋放內(nèi)存,提高效率。

struct ListNode
{
	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* _next;
	ListNode* _prev;
	int _data;
};
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 h;
	return 0;
}

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

內(nèi)置類(lèi)型:

若申請(qǐng)的是內(nèi)置類(lèi)型的空間,new和malloc,delete和free基本相似。new/delete 申請(qǐng)和釋放的是單個(gè)元素的空間,new[]和delete[]申請(qǐng)的是連續(xù)空間。new在空間申請(qǐng)失敗時(shí)會(huì)拋異常,malloc申請(qǐng)空間失敗則返回NULL。

自定義類(lèi)型:

new:

  1. 調(diào)用operator new函數(shù)申請(qǐng)空間。
  2. 在申請(qǐng)的空間調(diào)用構(gòu)造函數(shù),完成對(duì)象的構(gòu)造。

delete:

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

new arr[N]:

  1. 調(diào)用operator new[]函數(shù),在operator new[]中實(shí)際調(diào)用operator new函數(shù)完成N個(gè)對(duì)象空間的申請(qǐng)。
  2. 在申請(qǐng)的空間上執(zhí)行N次構(gòu)造函數(shù)。

delete []:

  1. 在釋放的空間上執(zhí)行N次析構(gòu)函數(shù),完成N個(gè)對(duì)象中資源的清理。
  2. 調(diào)用operator delete[]釋放空間,在operator delete[]中調(diào)用operator delete來(lái)釋放空間。

定位new表達(dá)式(placement-new)

??一般來(lái)說(shuō),使用new申請(qǐng)空間時(shí),是從系統(tǒng)堆上分配空間。申請(qǐng)所得的空間位置是根據(jù)當(dāng)時(shí)的內(nèi)存使用的實(shí)際情況來(lái)決定。但在某些特殊情況下,可能需要在已分配的特定內(nèi)存創(chuàng)建對(duì)象,這就是所說(shuō)的定位new(placement - new)。

??默認(rèn)情況下,如果new不能分配所需要的內(nèi)存空間,那么它會(huì)拋出一個(gè)類(lèi)型為bad_alloc的異常。我們可以改變使用new的方式來(lái)阻止其拋出異常:

//如果申請(qǐng)失敗,new會(huì)返回一個(gè)空指針(NULL)
int* p1 = new int;            //如果分配空間失敗,new會(huì)拋出std::bad_alloc
int* p2 = new (nothrow) int;  //如果分配空間失敗,new返回一個(gè)空指針

這種形式的new我們就稱為定位new。

定位new表達(dá)式允許我們向new傳遞額外的參數(shù)。如上的nothrow。將nothrow傳給new,即不能拋出異常。如果這種形式的new不能分配所需內(nèi)存,那么它會(huì)返回一個(gè)空指針。

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

1.相同點(diǎn):它們都是堆上申請(qǐng)空間并且手動(dòng)釋放。

2.malloc和free是函數(shù),new和delete是操作符。

3.malloc申請(qǐng)的空間不初始化,new申請(qǐng)的空間可以初始化。

4.malloc申請(qǐng)空間時(shí)需要計(jì)算所需空間的大小并且傳遞,new申請(qǐng)空間時(shí)只需在其后加上空間類(lèi)型即可。

5.malloc的返回值為void*,在使用時(shí)必須強(qiáng)轉(zhuǎn),new不需要,因?yàn)閚ew后跟的是空間的類(lèi)型。

6.malloc申請(qǐng)空間失敗時(shí)返回NULL,使用時(shí)需要判空,而new不需要判空,但是new需要捕獲異常。

7.申請(qǐng)自定義類(lèi)型對(duì)象時(shí),malloc/free只會(huì)開(kāi)辟空間,不會(huì)調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)處理空間,但new在申請(qǐng)空間后會(huì)調(diào)用構(gòu)造函數(shù)完成對(duì)象的初始化,delete在釋放空間前后調(diào)用析構(gòu)函數(shù)完成空間中資源的清理。

內(nèi)存泄漏及其危害

內(nèi)存泄漏(Memory Leak) 是指程序中已動(dòng)態(tài)分配的堆內(nèi)存由于某種原因?qū)е鲁绦蛭瘁尫呕蛘邿o(wú)法釋放,造成系統(tǒng)內(nèi)存的浪費(fèi),導(dǎo)致程序運(yùn)行速度減慢甚至系統(tǒng)崩潰等嚴(yán)重后果。內(nèi)存泄漏并不是指內(nèi)存在物理上的消失,而是應(yīng)用程序分配某段內(nèi)存后,因?yàn)殄e(cuò)誤設(shè)計(jì),失去了對(duì)該段內(nè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)越慢,最終卡死。

??常見(jiàn)的導(dǎo)致內(nèi)存泄漏的原因:

??c/c++程序中我們比較關(guān)心的兩種內(nèi)存泄漏:

1.堆內(nèi)存泄漏(Heap Leak)

堆內(nèi)存指程序執(zhí)行中需要通過(guò)malloc、realloc、realloc、new等從堆中分配內(nèi)存,用完后需通過(guò)調(diào)用free或者delete釋放。若程序的設(shè)計(jì)錯(cuò)誤導(dǎo)致這一部分內(nèi)存沒(méi)有被釋放掉,那么之后這塊空間將無(wú)法繼續(xù)使用,就會(huì)發(fā)生堆內(nèi)存泄漏。

2.系統(tǒng)資源泄漏

指程序使用系統(tǒng)分配的資源,比方套接字、文件描述符、管道等沒(méi)有使用對(duì)于的函數(shù)釋放掉,導(dǎo)致系統(tǒng)資源的浪費(fèi),嚴(yán)重則可導(dǎo)致系統(tǒng)的效能減少,系統(tǒng)執(zhí)行不穩(wěn)等。

??如何避免內(nèi)存泄漏:

1.工程前期設(shè)計(jì)規(guī)范,養(yǎng)成良好的編碼習(xí)慣。

2.提前預(yù)防。如智能指針等。

3.內(nèi)存泄漏工具的使用。(很多工具不靠譜,且收費(fèi)昂貴)

??內(nèi)存泄漏檢測(cè)工具:(來(lái)自百度百科)

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

相關(guān)文章

  • C語(yǔ)言超詳細(xì)講解棧的實(shí)現(xiàn)及代碼

    C語(yǔ)言超詳細(xì)講解棧的實(shí)現(xiàn)及代碼

    棧(stack)又名堆棧,它是一種運(yùn)算受限的線性表。限定僅在表尾進(jìn)行插入和刪除操作的線性表。這一端被稱為棧頂,相對(duì)地,把另一端稱為棧底。向一個(gè)棧插入新元素又稱作進(jìn)棧、入?;驂簵?,它是把新元素放到棧頂元素的上面,使之成為新的棧頂元素
    2022-04-04
  • VC隨機(jī)函數(shù)srand和rand用法

    VC隨機(jī)函數(shù)srand和rand用法

    VC中隨機(jī)函數(shù)最常用就是srand和rand(實(shí)際上是屬于標(biāo)準(zhǔn)C函數(shù)),其中srand負(fù)責(zé)設(shè)置隨機(jī)種子,rand則負(fù)責(zé)生成隨機(jī)數(shù)。使用此二隨機(jī)函數(shù)需要包含<stdlib.h>頭文件
    2016-11-11
  • C++實(shí)現(xiàn)LeetCode(114.將二叉樹(shù)展開(kāi)成鏈表)

    C++實(shí)現(xiàn)LeetCode(114.將二叉樹(shù)展開(kāi)成鏈表)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(114.將二叉樹(shù)展開(kāi)成鏈表),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C++基礎(chǔ)入門(mén)教程(七):一些比較特別的基礎(chǔ)語(yǔ)法總結(jié)

    C++基礎(chǔ)入門(mén)教程(七):一些比較特別的基礎(chǔ)語(yǔ)法總結(jié)

    這篇文章主要介紹了C++基礎(chǔ)入門(mén)教程(七):一些比較特別的基礎(chǔ)語(yǔ)法總結(jié),本文總結(jié)的都是一些特殊的語(yǔ)法,需要的朋友可以參考下
    2014-11-11
  • C語(yǔ)言從零探索函數(shù)的知識(shí)

    C語(yǔ)言從零探索函數(shù)的知識(shí)

    函數(shù)是一組一起執(zhí)行一個(gè)任務(wù)的語(yǔ)句。每個(gè) C 程序都至少有一個(gè)函數(shù),即主函數(shù) main() ,所有簡(jiǎn)單的程序都可以定義其他額外的函數(shù),讓我們一起來(lái)了解它
    2022-04-04
  • 深入探索C++中stack和queue的底層實(shí)現(xiàn)

    深入探索C++中stack和queue的底層實(shí)現(xiàn)

    這篇文章主要介紹了C++中的stack和dequeue的底層實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-09-09
  • C++實(shí)現(xiàn)基于EASYX庫(kù)掃描線算法

    C++實(shí)現(xiàn)基于EASYX庫(kù)掃描線算法

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)基于EASYX庫(kù)掃描線算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • C++指針與引用的異同

    C++指針與引用的異同

    這篇文章主要介紹了C++指針與引用的異同,文章以C++指針與引用的相關(guān)資料結(jié)合指針和引用的相同點(diǎn)和區(qū)別展開(kāi)詳細(xì)內(nèi)容,需要的朋友可以參考一下
    2021-11-11
  • 簡(jiǎn)單介紹C++中變量的引用

    簡(jiǎn)單介紹C++中變量的引用

    這篇文章主要簡(jiǎn)單介紹了C++中變量的引用,是C++入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-09-09
  • Qt項(xiàng)目打包的實(shí)現(xiàn)步驟

    Qt項(xiàng)目打包的實(shí)現(xiàn)步驟

    本文主要介紹了Qt項(xiàng)目打包的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05

最新評(píng)論