您好,登錄后才能下訂單哦!
這篇文章主要介紹了C語言與C++中內存管理的方法的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇C語言與C++中內存管理的方法文章都會有所收獲,下面我們一起來看看吧。
主要段及其分布
每個程序運行起來以后,它將擁有自己獨立的虛擬地址空間。這個虛擬地址空間的大小與操作系統的位數有關系。32位硬件平臺的虛擬地址空間的地址可以從0~2^32-1,即0x00000000~0xFFFFFFFF,總共4GB大小。64位硬件平臺的虛擬地址空間則會很大。C/C++程序在虛擬內存中的排布大概如下所示(僅僅列出了相關的主要段):
如上圖所示:
1、棧區(stack)— 由編譯器自動分配釋放 ,存放函數的參數值,局部變量的值等。其操作方式類似于數據結構中的棧。
2、堆區(heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。注意它與數據結構中的堆是兩回事,分配方式倒是類似于鏈表,注意不釋放的話會造成內存泄漏。
3、數據段(靜態區)(static)—,全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域, 未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。 - 程序結束后由系統釋放。
4、內存映射段是高效的I/O映射方式,用于裝載一個共享的動態內存庫。用戶可使用系統接口創建共享共享內存,做進程間通信。
5、代碼段—存放函數體的二進制代碼,直接的操作數也是存儲在這個位置的。如int a=4;。
C語言中使用malloc/calloc/realloc/free四個函數來進行動態內存管理
1、malloc:用來動態申請一塊內存,但不初始化。
2、calloc: 動態申請一塊內存,但會將申請出的內存初始化為0。
3、realloc: 當申請出的內存不夠用時,會使用realloc來動態擴容(會有一定程度的消耗)。
4、free: 用來釋放動態申請的的內存(當內存不用時一定要使用free來釋放它,否則會造成內存泄漏)
因為C++是兼容C的也可以使用上述的幾個函數來進行內存管理,但是C++中引入了new/delete兩個操作符來進行內存的申請和釋放。
1、操作內置類型
//申請單個對象 int *p1=new int;//動態申請一塊int類型的空間。 int *p2=new int(3);//動態申請一塊int類型的空間,并將其初始化。 delete p1; delete p2; //動態申請一塊連續空間 int *p3=new int[10];//[]中是對象個數 //釋放 delete [] p3;
注意:申請和釋放單個元素的空間,使用new和delete操作符,申請和釋放連續的空間,使用new[]和delete[]。
2、操作自定義類型
class Test { public: Test() : _data(0) { cout<<"Test():"<<this<<endl; } ~Test() { cout<<"~Test():"<<this<<endl; } private: int _data; }; int main() { //申請單個自定義類型的空間 Test* p1=new Test; delete p1; //申請多個自定義類型的連續空間 Test* p2= new Test[10]; delete [] p2; return 0; }
注意:在申請自定義類型的空間時,new會調用構造函數,delete會調用析構函數,而malloc與free不會。
new和delete是用戶進行動態內存申請和釋放的操作符,operator new和operator delete是系統提供的全局函數,new在底層調用operator new全局函數來申請空間,delete在底層通過operator delete全局函數來釋放空間。
operator new:該函數實際通過malloc來申請空間,當malloc申請空間成功時直接返回;申請空間失敗,嘗試執行空間不足應對措施,如果改應對措施用戶1設置了,則繼續申請,否則拋異常。
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:該函數實際通過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; }
1、內置類型
如果申請的是內置類型的空間,new和malloc,delete和free基本類似,不同的地方是:new/delete申請和釋放的是單個元素的空間,new[]和delete[]申請的是連續空間,而且new在申請空間失敗時會拋異常,malloc會返回NULL
2、自定義類型
new的原理
1、調用operator new 函數申請空間
2、在申請的空間上執行構造函數,完成對象的構造
delete的原理
1、調用operatordelete 函數釋放空間
2、在空間上執行析構函數,完成對象中資源的清理工作
new T[N]的原理
1、調用operator new[]函數,在operator new[]中實際調用operator new函數完成N個對象空間的申請
2、在申請的空間上執行N次構造函數
delete[]的原理
1、在釋放的對象空間上執行N次析構函數,完成N個對象中資源的清理
2、調用operator delete[]釋放空間,實際在operator delete[]中調用operator delete來釋放空間
定位new表達式是在已分配的原始內存空間中調用構造函數初始化一個對象。
使用格式:
new (place_address) type或者new (place_address) type(initializer-list)
place_address必須是一個指針,initializer-list是類型的初始化列表
使用場景:
定位new表達式在實際中一般是配合內存池使用。因為內存池分配出的內存沒有初始化,所以如果是自定義類型的對象,需要使用new的定義表達式進行顯示調構造函數進行初始化。
class Test { public: Test() : _data(0) { cout<<"Test():"<<this<<endl; } ~Test() { cout<<"~Test():"<<this<<endl; } private: int _data; }; void Test() { // pt現在指向的只不過是與Test對象相同大小的一段空間,還不能算是一個對象,因為構造函數沒有執行 Test* pt = (Test*)malloc(sizeof(Test)); new(pt) Test; // 注意:如果Test類的構造函數有參數時,此處需要傳參 }
1、 屬性
new/delete是C++關鍵字,需要編譯器支持。malloc/free是庫函數,需要頭文件支持。
2、 參數
使用new操作符申請內存分配時無須指定內存塊的大小,編譯器會根據類型信息自行計算。而malloc則需要顯式地指出所需內存的尺寸。
3、 返回類型
new操作符內存分配成功時,返回的是對象類型的指針,類型嚴格與對象匹配,無須進行類型轉換,故new是符合類型安全性的操作符。而malloc內存分配成功則是返回void * ,需要通過強制類型轉換將void*指針轉換成我們需要的類型。
4、 分配失敗
new內存分配失敗時,會拋出bac_alloc異常。malloc分配內存失敗時返回NULL。
5、 自定義類型
new會先調用operator new函數,申請足夠的內存(通常底層使用malloc實現)。然后調用類型的構造函數,初始化成員變量,最后返回自定義類型指針。delete先調用析構函數,然后調用operator delete函數釋放內存(通常底層使用free實現)。
malloc/free是庫函數,只能動態的申請和釋放內存,無法強制要求其做自定義類型對象構造和析構工作。
6、 重載
C++允許重載new/delete操作符,特別的,布局new的就不需要為對象分配內存,而是指定了一個地址作為內存起始區域,new在這段內存上為對象調用構造函數完成初始化工作,并返回此地址。而malloc不允許重載。
7、 內存區域
new操作符從自由存儲區(free store)上為對象動態分配內存空間,而malloc函數從堆上動態分配內存。自由存儲區是C++基于new操作符的一個抽象概念,凡是通過new操作符進行內存申請,該內存即為自由存儲區。而堆是操作系統中的術語,是操作系統所維護的一塊特殊內存,用于程序的內存動態分配,C語言使用malloc從堆上分配內存,使用free釋放已分配的對應內存。自由存儲區不等于堆,如上所述,布局new就可以不位于堆中。
1、什么是內存泄漏,內存泄漏的危害什么是內存泄漏:內存泄漏指因為疏忽或錯誤造成程序未能釋放已經不再使用的內存的情況。內存泄漏并不是指內存在物理上的消失,而是應用程序分配某段內存后,因為設計錯誤,失去了對該段內存的控制,因而造成了內存的浪費。
內存泄漏的危害:長期運行的程序出現內存泄漏,影響很大,如操作系統、后臺服務等等,出現內存泄漏會導致響應越來越慢,最終卡死。
2、內存泄漏分類
C/C++程序中一般我們關心兩種方面的內存泄漏:
堆內存泄漏
堆內存指的是程序執行中依據須要分配通過malloc / calloc / realloc / new等從堆中分配的一塊內存,用完后必須通過調用相應的 free或者delete 刪掉。假設程序的設計錯誤導致這部分內存沒有被釋放,那么以后這部分空間將無法再被使用,就會產生Heap Leak
系統資源泄漏
指程序使用系統分配的資源,比方套接字、文件描述符、管道等沒有使用對應的函數釋放掉,導致系統資源的浪費,嚴重可導致系統效能減少,系統執行不穩定
3、如何避免內存泄漏
工程前期良好的設計規范,養成良好的編碼規范,申請的內存空間記著匹配的去釋放。ps:這個理想狀態。但是如果碰上異常時,就算注意釋放了,還是可能會出問題。需要下一條智能指針來管理才有保證。
采用RAII思想或者智能指針來管理資源。
有些公司內部規范使用內部實現的私有內存管理庫。這套庫自帶內存泄漏檢測的功能選項。
出問題了使用內存泄漏工具檢測。ps:不過很多工具都不夠靠譜,或者收費昂貴。
關于“C語言與C++中內存管理的方法”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“C語言與C++中內存管理的方法”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。