日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++ 动态内存管理:c/c++的动态内存管理,new/delete,operator new/delete,placement-new, 内存泄漏

發布時間:2024/4/11 c/c++ 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++ 动态内存管理:c/c++的动态内存管理,new/delete,operator new/delete,placement-new, 内存泄漏 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  • c/c++的動態內存管理
  • new/delete
  • opeartor new/delete
  • placement-new
  • 內存泄漏

c/c++的動態內存管理

在開始之前首先要了解c和c++的內存分布,我簡單的畫了一個圖

  • 棧又叫堆棧,非靜態局部變量/函數參數/返回值等等,棧是向下增長的。
  • 內存映射段是高效的I/O映射方式,用于裝載一個共享的動態內存庫。用戶可使用系統接口創建共享共 享內存,做進程間通信。
  • 堆用于程序運行時動態內存分配,堆是可以上增長的。
  • 數據段–存儲全局數據和靜態數據。
  • 代碼段–可執行的代碼/只讀常量。
  • 之前我寫過一篇關于c語言動態內存管理的博客:
    https://blog.csdn.net/qq_35423154/article/details/103283679

    這次再將這個問題引申到c++上,談一談c++對c動態內存管理的擴充和改進。

    首先,我們需要找到,new/delete與c語言的malloc/free之間有什么區別,為什么有了malloc和free還要實現new和delete呢?new和delete又在malloc和free上有什么改進呢?


    new/delete

    首先來簡單介紹一下new和delete的用法

    int main() {int* data1 = new int;//動態分配一個int的空間int* data2 = new int(15);//動態分配一個int的空間,并將它初始化成15int* arr = new int[10];//動態分配具有10的int的空間//這里需要注意[]中寫的是該類型數據的個數,而()是初始化的內容delete data1;delete data2;delete[] arr;//對于單個數據直接用delete加上名字,如果是多個則需要在delete后面加上[] }

    對于內置類型,malloc/free和new/delete的用法類似,功能也差不多,下面來試試自定義類型。

    class Date { public:Date(int year = 2020, int month = 4, int day = 28):_year(year),_month(month),_day(day){}~Date(){cout << "調用析構函數" << endl;}private:int _year;int _month;int _day; };int main() {Date* d1 = (Date*)malloc(sizeof(Date));//使用c語言的malloc和freeDate* d2 = new Date();//使用c++的new和deletefree(d1);delete(d2);return 0; }

    接下來先進入調試,看看他們有什么區別

    可以看到d1雖然創建了,但里面都是隨機值,而d2自動調用了默認的構造函數。

    然后再看看free和delete


    調用后會發現他們都會清除數據,但是delete會再調用一次析構函數。

    下面來看看他們的匯編有什么不同


    這里可以看到,它們的基本操作類似,只是new和delete多調用了構造函數和析構函數,但是new還調用了一個operator new,那又是什么呢?


    opeartor new/delete

    這里我找來了operator new和delete的代碼

    new和delete是用戶進行動態內存申請和釋放的操作符,operator new 和operator delete是系統提供的
    全局函數,new在底層調用operator new全局函數來申請空間,delete在底層通過operator delete全局函數來釋放空間。

    void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc) {// try to allocate size bytesvoid* p;while ((p = malloc(size)) == 0)if (_callnewh(size) == 0){// report no memory// throw a bad_alloc exceptionstatic const std::bad_alloc nomem;_RAISE(nomem);}return (p); } 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_FINALLYreturn; }

    我們可以看到, opeartor new其實底層調用的還是malloc,但是它改進了一些東西,比如c中分配失誤時返回NULL,而它這里是拋出一個異常,operator和free也類似,于是我百度了一下,了解他們為什么要這樣實現。

    我得到的結果是,因為c是面向過程,c++是面向對象,這兩個函數其實就是從面向過程到面向對象之間的一種過渡,增添了異常和一些內容,再從opeartor new/delete到new/delete又增添了調用構造函數和析構函數,更加符合面向對象的思想。

    總結

    調用new/delete其實底層會這樣實現。
    1.動態分配空間/釋放空間(調用operator new/delete->調用malloc/free)

    2.自定義類型(調用構造函數/析構函數)

    如果是 new[]/delete[]
    則分配一段連續的空間,并且調用n次 構造函數/析構函數

    內置類型:

    對于內置類型,new/delete其實和malloc/free基本類似,只不過new和delete失敗后會拋出一個bad_allocy異常,而malloc/free會返回一個NULL。
    同時new會初始化創建的數據

    自定義類型:

    1.調用operator new/delete 分配空間/釋放空間
    2.調用構造函數/析構函數

    malloc/free和new/delete的共同點是:都是從堆上申請空間,并且需要用戶手動釋放。不同的地方是:

  • malloc和free是函數,new和delete是操作符
  • malloc申請的空間不會初始化,new可以初始化
  • malloc申請空間時,需要手動計算空間大小并傳遞,new只需在其后跟上空間的類型即可
  • malloc的返回值為void*, 在使用時必須強轉,new不需要,因為new后跟的是空間的類型
  • malloc申請空間失敗時,返回的是NULL,因此使用時必須判空,new不需要,但是new需要捕獲異常
  • 申請自定義類型對象時,malloc/free只會開辟空間,不會調用構造函數與析構函數,而new在申請空間 后會調用構造函數完成對象的初始化,delete在釋放空間前會調用析構函數完成空間中資源的清理

  • placement-new

    placement-new也就是定位new表達式,是在已分配的原始內存空間中調用構造函數初始化一個對象。這一步其實就是new再調用operator后再執行的那一步。

    在實際中我們也會經常使用到定位new表達式,因為內存池分配出來的內存沒有初始化,所以如果是自定義類型的對象,我們需要使用定位new表達式來顯式調用構造函數來為其初始化。

    下面介紹一下用法

    使用格式:
    new (place_address) type或者new (place_address)
    type(initializer-list) place_address必須是一個指針,initializer-list是類型的初始化列表

    int main() {Date* d1 = (Date*)malloc(sizeof(Date));new(d1) Date;//對于剛剛那個日期類,在使用malloc分配后再用定位new來顯式調用構造函數。return 0; }

    內存泄漏(引用)

    什么是內存泄漏

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

    內存泄漏的危害:

    長期運行的程序出現內存泄漏,影響很大,如操作系統、后臺服務等等,出現內存泄漏會導致響應越來越慢,最終卡死。

    一般來說,內存泄漏大多數存在于c/c++程序中,因為現在的主流語言如java,python,c#等都具有完善的垃圾回收機制,所以一般不會存在內存泄漏的情況,但也因為這種上述語言存在這種垃圾回收機制,所以在回收內存的時候也會花費寶貴的CPU資源,導致速度有所下降,所以對于c和c++,這是一把雙刃劍,全靠程序員如何掌控。

    C/C++程序中一般我們關心兩種方面的內存泄漏:

    • 堆內存泄漏(Heap leak) 堆內存指的是程序執行中依據須要分配通過malloc / calloc / realloc / new等從堆中分配的一塊內存,用完后必須通過調用相應的 free或者delete
      刪掉。假設程序的設計錯誤導致這部分內存沒有被釋放,那么以后這部分空間將無法再被使用,就會產生Heap Leak。
    • 系統資源泄漏 指程序使用系統分配的資源,比方套接字、文件描述符、管道等沒有使用對應的函數釋放掉,導致系統資源的浪費,嚴重可導致系統效能減少,系統執行不穩定。

    如何避免內存泄漏

  • 工程前期良好的設計規范,養成良好的編碼規范,申請的內存空間記著匹配的去釋放。ps:這個理想狀 態。但是如果碰上異常時,就算注意釋放了,還是可能會出問題。需要下一條智能指針來管理才有保 證。
  • 采用RAII思想或者智能指針來管理資源。
  • 有些公司內部規范使用內部實現的私有內存管理庫。這套庫自帶內存泄漏檢測的功能選項。
  • 出問題了使用內存泄漏工具檢測。ps:不過很多工具都不夠靠譜,或者收費昂貴。 總結一下: 內存泄漏非常常見,解決方案分為兩種:1、事前預防型。如智能指針等。2、事后查錯型。如泄漏檢測工 具
  • 總結

    以上是生活随笔為你收集整理的C++ 动态内存管理:c/c++的动态内存管理,new/delete,operator new/delete,placement-new, 内存泄漏的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。