日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

c++动态内存管理

發(fā)布時(shí)間:2023/11/30 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++动态内存管理 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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

虛擬地址空間分布

  • 棧又叫堆棧,非靜態(tài)局部變量/函數(shù)參數(shù)/返回值等等,棧是向下增長(zhǎng)的。
  • 內(nèi)存映射段是高效的I/O映射方式,用于裝載一個(gè)共享的動(dòng)態(tài)內(nèi)存庫(kù)。用戶可使用系統(tǒng)接口創(chuàng)建共享共 享內(nèi)存,做進(jìn)程間通信。(Linux課程如果沒(méi)學(xué)到這塊,現(xiàn)在只需要了解一下)
  • 堆用于程序運(yùn)行時(shí)動(dòng)態(tài)內(nèi)存分配,堆是可以上增長(zhǎng)的。
  • 數(shù)據(jù)段–存儲(chǔ)全局?jǐn)?shù)據(jù)和靜態(tài)數(shù)據(jù)。
  • 代碼段–可執(zhí)行的代碼/只讀常量。
  • 為什么操作系統(tǒng)要?jiǎng)澐诌@些區(qū)段

    答:為了找數(shù)據(jù),存數(shù)據(jù)方便

    以下的代碼分別在虛擬地址空間中的哪個(gè)段

    int globalVar = 1; //數(shù)據(jù)段static int staticGlobalVar = 1; //數(shù)據(jù)段void Test() { static int staticVar = 1; //數(shù)據(jù)端int localVar = 1; //棧int num1[10] = {1, 2, 3, 4}; //棧char char2[] = "abcd"; //char數(shù)組在棧,里面存儲(chǔ)的abcd字符串常量在代碼段char* pChar3 = "abcd"; //pChar指針在棧上,里面的abcd字符串常量在代碼段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 (ptr3);}

    sizeof與strlen的區(qū)別

  • sizeof()是運(yùn)算符,strlen()是庫(kù)函數(shù)
  • sizeof()在編譯時(shí)計(jì)算好了,strlen()在運(yùn)行時(shí)計(jì)算
  • sizeof()計(jì)算出對(duì)象使用的最大字節(jié)數(shù),strlen()計(jì)算字符串的實(shí)際長(zhǎng)度
  • sizeof()的參數(shù)類型多樣化(數(shù)組,指針,對(duì)象,函數(shù)都可以),strlen()的參數(shù)必須是字符型指針(傳入數(shù)組時(shí)自動(dòng)退化為指針)
  • c語(yǔ)言動(dòng)態(tài)開(kāi)辟空間

    動(dòng)態(tài)申請(qǐng)空間的方式
  • malloc void * malloc ( size_t size );
  • callocvoid * calloc ( size_t num, size_t size );
  • reallocvoid * realloc ( void * ptr, size_t size );
  • 相同點(diǎn):

    • 都是從堆上開(kāi)辟空間
    • 返回值類型都是void*
    • 申請(qǐng)空間失敗,返回的都是NULL
    • 申請(qǐng)的空間都需要手動(dòng)釋放
    • 在接收返回值時(shí)都需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換

    不同點(diǎn)

    malloc:

    • 參數(shù):字節(jié)數(shù),
    • 不會(huì)對(duì)申請(qǐng)的空間進(jìn)行初始化,
    • 在接收返回值時(shí)必須強(qiáng)制類型轉(zhuǎn)換
    • 如果申請(qǐng)空間失敗,返回值NULL,使用前必須判斷是否為空

    calloc:

    • 參數(shù)列表不同:void * calloc ( size_t num, size_t size );,第一個(gè)為元素個(gè)數(shù),第二個(gè)為單個(gè)元素大小
    • 函數(shù)功能差異:calloc會(huì)將申請(qǐng)的空間初始化為0

    realloc

    • 參數(shù)列表:void * realloc ( void * ptr, size_t size );
    • 函數(shù)功能:將ptr所指向的空間調(diào)整到size字節(jié),如果ptr為空----->函數(shù)行為與malloc相同
    • ptr非空,判斷是縮小還是增大,縮小的話,對(duì)原空間進(jìn)行調(diào)整,最后返回該空間的首地址,擴(kuò)大的話,有兩種情況:1. 擴(kuò)大一點(diǎn),2.擴(kuò)大很多
    1.如果當(dāng)前空間后面有足夠的空間能夠支持size字節(jié)的話,直接擴(kuò)容 2.如果沒(méi)有足夠的空間,realloc做四件事情,第一:申請(qǐng)新空間,第二:拷貝元素,第三:釋放舊空間,第四:返回新空間的地址
    動(dòng)態(tài)釋放方式

    手動(dòng)free

    malloc

    int* p =(int*)malloc(10*sizeof(int));

    40字節(jié)-----堆上,只要把空間分配給一個(gè)應(yīng)用程序,那么其他應(yīng)用程序就用不了。系統(tǒng)必須對(duì)malloc申請(qǐng)的空間進(jìn)行管理。
    一般malloc申請(qǐng)空間時(shí),比如申請(qǐng)40個(gè)字節(jié),除了申請(qǐng)的40字節(jié)空間,他還會(huì)在前面加一個(gè)結(jié)構(gòu)體來(lái)管理40字節(jié)的空間,在后面加4個(gè)字節(jié)的空間用來(lái)防止越界

    詳解c中動(dòng)態(tài)內(nèi)存分配

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

    C語(yǔ)言內(nèi)存管理方式在C++中可以繼續(xù)使用,但有些地方就無(wú)能為力而且使用起來(lái)比較麻煩,因此C++又提出 了自己的內(nèi)存管理方式:通過(guò)new和delete操作符進(jìn)行動(dòng)態(tài)內(nèi)存管理。

    new申請(qǐng)內(nèi)置類型

    int main() {//new 申請(qǐng)單個(gè)類型元素的空間----默認(rèn)情況下new出的空間在堆上int *p1 = new int;int *p2 = new int(10);int *p3 = new int[10];int *p4 = new int[10]{1, 2, 3, 4, 5, 6, 7, 8, 9, 0};delete p1;delete p2;delete[] p3;delete[] p4;return 0; }
  • new和delete不是函數(shù),c++提供的新的操作符
  • new/new[] 只需在其后跟空間的類型,不需要傳遞字節(jié)數(shù)
  • new后跟的就是空間的類型,不需要強(qiáng)制類型轉(zhuǎn)換
  • new/new[]可以進(jìn)行初始化
  • new的結(jié)果不需要判空
    注意:申請(qǐng)和釋放單個(gè)元素的空間,使用new和delete操作符,申請(qǐng)和釋放連續(xù)的空間,使用new[]和 delete[]
  • 如果沒(méi)有匹配

    如果申請(qǐng)的是內(nèi)置類型的空間,沒(méi)有匹配的話,不會(huì)產(chǎn)生任何后果

    void Test() {int *p1 = (int *)malloc(sizeof(int)* 4);int *p2 = (int *)malloc(sizeof(int)* 4);delete p1;delete p2;int *p3 = new int;int *p4 = new int;free(p3);delete[]p4;int *p5 = new int[10];int *p6 = new int[10];free(p5);delete p6; }

    new申請(qǐng)自定義類型數(shù)據(jù)

    未進(jìn)行匹配使用

    //自定義類型 class Test { public:Test(){_data = 10;cout << "Test():" << this <<endl;}~Test(){cout << "~Test()" << this << endl;} private:int _data;};void Test2() {Test *p1 = (Test *)malloc(sizeof(Test)* 4);//Test *p2 = (Test *)malloc(sizeof(Test)* 4);delete p1;//delete[] p2;Test *p3 = new Test;Test *p4 = new Test;free(p3);delete[]p4;Test *p5 = new Test[10];Test *p6 = new Test[10];free(p5);delete p6; }
  • 對(duì)于自定義類型,只要設(shè)計(jì)到[]不匹配,肯定崩潰
  • new會(huì)調(diào)用構(gòu)造函數(shù),而free不會(huì)調(diào)用析構(gòu)函數(shù)----對(duì)象中的資源不會(huì)被銷毀—內(nèi)存泄露
  • malloc申請(qǐng)空間時(shí)不會(huì)調(diào)用構(gòu)造函數(shù)—申請(qǐng)的是與對(duì)象大小相同的一塊內(nèi)存空間,不能將該塊內(nèi)存空間看成是一個(gè)對(duì)象
  • delete需要調(diào)用析構(gòu)函數(shù)
  • operator new與operator delete函數(shù)

    new是先調(diào)用構(gòu)造函數(shù),還是先申請(qǐng)空間?

    第一件事情:申請(qǐng)內(nèi)存空間,第二才是調(diào)用構(gòu)造函數(shù),完成對(duì)象的初始化

    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在底層通過(guò)operator delete全局 函數(shù)來(lái)釋放空間。

    /* 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) //內(nèi)存空間不足的應(yīng)對(duì)措施 { // report no memory // 如果申請(qǐng)內(nèi)存失敗了,這里會(huì)拋出bad_alloc 類型異常 static const std::bad_alloc nomem; _RAISE(nomem); }return (p); }

    循環(huán)調(diào)用malloc來(lái)不斷申請(qǐng)空間,直到申請(qǐng)成功,

  • malloc申請(qǐng)----->成功----->直接返回
  • malloc申請(qǐng)------>失敗(內(nèi)存空間不足)------->檢測(cè)是否提供空間不足的應(yīng)對(duì)措施,提供:繼續(xù)申請(qǐng),未提供:拋異常
  • /* operator delete: 該函數(shù)最終是通過(guò)free來(lái)釋放空間的 */ void operator delete(void *pUserData) { //_CrtMemBlockHeader 這個(gè)就是malloc申請(qǐng)內(nèi)存時(shí)前面的哪個(gè)結(jié)構(gòu)體_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_FINALLYreturn; }

    delete p;

  • 調(diào)用析構(gòu)函數(shù)釋放對(duì)象中的資源-----對(duì)象中的資源
  • 調(diào)用void operator delete(void *p) 釋放對(duì)象本身的空間
  • 總結(jié)

    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)釋放空間的

    void* operator new(size_t size,const char* file,const char* funname,size_t line) {cout << file << "-" << funname << "-" << line << "-" << size << endl;return malloc(size); }void operator delete(void *p, const char* file, const char* funname, size_t line) {cout << file << "-" << funname << "-" << line << "-" << endl;free(p); } #define new new(__FILE__, __FUNCDNAME__, __LINE__)int main() {int *p = new int;delete p;system("pause");return 0; }

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

    內(nèi)置類型

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

    自定義類型

    • new的原理
    • 調(diào)用operator new函數(shù)申請(qǐng)空間
    • 在申請(qǐng)的空間上執(zhí)行構(gòu)造函數(shù),完成對(duì)象的構(gòu)造
    • delete的原理
    • 在空間上執(zhí)行析構(gòu)函數(shù),完成對(duì)象中資源的清理工作
    • 調(diào)用operator delete函數(shù)釋放對(duì)象的空間
    • new T[N]的原理
    • 調(diào)用operator new[]函數(shù),在operator new[]中實(shí)際調(diào)用operator new函數(shù)完成N個(gè)對(duì)象空間的申 請(qǐng)
    • 在申請(qǐng)的空間上執(zhí)行N次構(gòu)造函數(shù)
    • delete[]的原理
    • 在釋放的對(duì)象空間上執(zhí)行N次析構(gòu)函數(shù),完成N個(gè)對(duì)象中資源的清理
    • 調(diào)用operator delete[]釋放空間,實(shí)際在operator delete[]中調(diào)用operator delete來(lái)釋放空間

    內(nèi)存碎片化

    如果每回一小塊一小塊申請(qǐng)內(nèi)存,就會(huì)造成內(nèi)存的浪費(fèi)。所以c++有一個(gè)現(xiàn)成的內(nèi)存池就是空間配置器
    以下代碼對(duì)鏈表的節(jié)點(diǎn)ListNode通過(guò)重載類專屬 operator new/ operator delete,實(shí)現(xiàn)鏈表節(jié) 點(diǎn)使用內(nèi)存池申請(qǐng)和釋放內(nèi)存,提高效率。

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

    定位new表達(dá)式

    在已經(jīng)存在的空間上執(zhí)行構(gòu)造函數(shù)
    使用格式:
    new (place_address) type或者new (place_address) type(initializer-list)
    place_address必須是一個(gè)指針,initializer-list是類型的初始化列表
    使用場(chǎng)景:
    定位new表達(dá)式在實(shí)際中一般是配合內(nèi)存池使用。因?yàn)閮?nèi)存池分配出的內(nèi)存沒(méi)有初始化,所以如果是自定義類型的對(duì)象,需要使用new的定義表達(dá)式進(jìn)行顯示調(diào)構(gòu)造函數(shù)進(jìn)行初始化

    class Test { public: Test() : _data(0) { cout << "Test():" << this << endl; }~Test() { cout << "~Test():" << this << endl; } private: int _data; }; int main() {Test* pt = (Test*)malloc(sizeof(Test));new(pt)Test;//delete pt;pt->~Test();system("pause");return 0; }

    關(guān)于c++動(dòng)態(tài)管理方面的題目

    題目總結(jié)的鏈接

    總結(jié)

    以上是生活随笔為你收集整理的c++动态内存管理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。