最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C/C++深入講解內存管理

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

C/C++內存分布

??首先我們來看一看以下代碼中變量在內存中的存儲位置。

c/c++內存分配圖:

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

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

3.堆用于程序運行時動態(tài)內存分配,堆上可以向上增長的。

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

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

C語言中的動態(tà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 - 堆上動態(tài)開辟空間

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

calloc - 針對已經(jīng)有的空間進行擴容 (原地擴容或異地擴容)

C++的內存管理

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

new和delete操作內置類型::

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

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

new和delete操作自定義類型::

注意: 在申請自定義類型的空間時,new會調用構造函數(shù),delete會調用析構函數(shù),而malloc和free不會。

??對于以上總結一下:

1.c++中如果是申請內置類型對象或者數(shù)組,malloc和new沒有什么區(qū)別。

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

3.建議在c++中,無論是自定義類型還是內置類型的申請和釋放,盡量使用new和delete。

operator new與operator delete函數(shù)

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

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

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

/*
operator new:該函數(shù)實際通過malloc來申請空間,當malloc申請空間成功時直接返回;申請空間失敗,
嘗試執(zhí)行空間不足應對措施,如果改應對措施用戶設置了,則繼續(xù)申請,否則拋異常。
*/
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
			// 如果申請內存失敗了,這里會拋出bad_alloc 類型異常
			static const std::bad_alloc nomem;
			_RAISE(nomem);
		}
	return (p);
}
/*
operator delete: 該函數(shù)最終是通過free來釋放空間的
*/
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的實現(xiàn)
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)

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

operator new的使用案例:

struct ListNode
{
	ListNode(int data = 0)
		:_next(nullptr)
		,_prev(nullptr)
		,_data(data)
	{}
	ListNode* _next;
	ListNode* _prev;
	int _data;
};
//operator new的用法跟malloc和free是一樣的,都是在堆上申請空間
//只是申請空間失敗后的處理方式不一樣,malloc失敗返回NULL,operator new失敗以后拋異常
int main()
{
	//C語言
	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);
	}
	//開辟空間失敗,捕獲異常信息
	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語言  ->  A* p = (A*)malloc(sizeof(A));
	//等價于直接用 A* p = new A;
	A* p = (A*)operator new(sizeof(A));
	new(p)A; // new(p)A(2);  定位new,placement-new,顯示調用構造函數(shù)初始化這塊空間對象
	//等價于 delete p
	p->~A();  //析構函數(shù)可以顯示調用
	operator delete(p);
	return 0;
}

operator new與operator delete的類專屬重載

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

??以下代碼演示了,針對鏈表的節(jié)點ListNode通過重載類專屬 operator new / operator delete ,實現(xiàn)鏈表節(jié)點使用內存池申請和釋放內存,提高效率。

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的實現(xiàn)原理

內置類型:

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

自定義類型:

new:

  1. 調用operator new函數(shù)申請空間。
  2. 在申請的空間調用構造函數(shù),完成對象的構造。

delete:

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

new arr[N]:

  1. 調用operator new[]函數(shù),在operator new[]中實際調用operator new函數(shù)完成N個對象空間的申請。
  2. 在申請的空間上執(zhí)行N次構造函數(shù)。

delete []:

  1. 在釋放的空間上執(zhí)行N次析構函數(shù),完成N個對象中資源的清理。
  2. 調用operator delete[]釋放空間,在operator delete[]中調用operator delete來釋放空間。

定位new表達式(placement-new)

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

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

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

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

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

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

1.相同點:它們都是堆上申請空間并且手動釋放。

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

3.malloc申請的空間不初始化,new申請的空間可以初始化。

4.malloc申請空間時需要計算所需空間的大小并且傳遞,new申請空間時只需在其后加上空間類型即可。

5.malloc的返回值為void*,在使用時必須強轉,new不需要,因為new后跟的是空間的類型。

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

7.申請自定義類型對象時,malloc/free只會開辟空間,不會調用構造函數(shù)和析構函數(shù)處理空間,但new在申請空間后會調用構造函數(shù)完成對象的初始化,delete在釋放空間前后調用析構函數(shù)完成空間中資源的清理。

內存泄漏及其危害

內存泄漏(Memory Leak) 是指程序中已動態(tài)分配的堆內存由于某種原因導致程序未釋放或者無法釋放,造成系統(tǒng)內存的浪費,導致程序運行速度減慢甚至系統(tǒng)崩潰等嚴重后果。內存泄漏并不是指內存在物理上的消失,而是應用程序分配某段內存后,因為錯誤設計,失去了對該段內存的控制。

??內存泄漏的危害:長期運行的程序出現(xiàn)內存泄漏,影響很大,如操作系統(tǒng)、后臺服務等等,出現(xiàn)內存泄漏會導致響應越來越慢,最終卡死。

??常見的導致內存泄漏的原因:

??c/c++程序中我們比較關心的兩種內存泄漏:

1.堆內存泄漏(Heap Leak)

堆內存指程序執(zhí)行中需要通過malloc、realloc、realloc、new等從堆中分配內存,用完后需通過調用free或者delete釋放。若程序的設計錯誤導致這一部分內存沒有被釋放掉,那么之后這塊空間將無法繼續(xù)使用,就會發(fā)生堆內存泄漏。

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

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

??如何避免內存泄漏:

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

2.提前預防。如智能指針等。

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

??內存泄漏檢測工具:(來自百度百科)

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

相關文章

最新評論

灌阳县| 京山县| 临夏县| 剑阁县| 财经| 赣榆县| 明光市| 萝北县| 麻阳| 永仁县| 昌乐县| 沧州市| 南涧| 那曲县| 黔南| 永胜县| 华池县| 于田县| 舟曲县| 安丘市| 巍山| 虞城县| 郯城县| 五华县| 荥阳市| 兴国县| 曲松县| 周宁县| 宜兰县| 舒城县| 班戈县| 清徐县| 潼南县| 潜江市| 抚远县| 叙永县| 罗城| 辉南县| 桂东县| 四子王旗| 柳州市|