C++ 动态内存管理:c/c++的动态内存管理,new/delete,operator new/delete,placement-new, 内存泄漏
- c/c++的動態內存管理
- new/delete
- opeartor new/delete
- placement-new
- 內存泄漏
c/c++的動態內存管理
在開始之前首先要了解c和c++的內存分布,我簡單的畫了一個圖
之前我寫過一篇關于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全局函數來釋放空間。
我們可以看到, 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的共同點是:都是從堆上申請空間,并且需要用戶手動釋放。不同的地方是:
placement-new
placement-new也就是定位new表達式,是在已分配的原始內存空間中調用構造函數初始化一個對象。這一步其實就是new再調用operator后再執行的那一步。
在實際中我們也會經常使用到定位new表達式,因為內存池分配出來的內存沒有初始化,所以如果是自定義類型的對象,我們需要使用定位new表達式來顯式調用構造函數來為其初始化。
下面介紹一下用法
使用格式:
new (place_address) type或者new (place_address)
type(initializer-list) place_address必須是一個指針,initializer-list是類型的初始化列表
內存泄漏(引用)
什么是內存泄漏
內存泄漏指因為疏忽或錯誤造成程序未能釋放已經不再使用的內存的情況。內存泄漏并不是指內存在物理上的消失,而是應用程序分配某段內存后,因為設計錯誤,失去了對該段內存的控制,因而造成了內存的浪費。
內存泄漏的危害:
長期運行的程序出現內存泄漏,影響很大,如操作系統、后臺服務等等,出現內存泄漏會導致響應越來越慢,最終卡死。
一般來說,內存泄漏大多數存在于c/c++程序中,因為現在的主流語言如java,python,c#等都具有完善的垃圾回收機制,所以一般不會存在內存泄漏的情況,但也因為這種上述語言存在這種垃圾回收機制,所以在回收內存的時候也會花費寶貴的CPU資源,導致速度有所下降,所以對于c和c++,這是一把雙刃劍,全靠程序員如何掌控。
C/C++程序中一般我們關心兩種方面的內存泄漏:
- 堆內存泄漏(Heap leak) 堆內存指的是程序執行中依據須要分配通過malloc / calloc / realloc / new等從堆中分配的一塊內存,用完后必須通過調用相應的 free或者delete
刪掉。假設程序的設計錯誤導致這部分內存沒有被釋放,那么以后這部分空間將無法再被使用,就會產生Heap Leak。 - 系統資源泄漏 指程序使用系統分配的資源,比方套接字、文件描述符、管道等沒有使用對應的函數釋放掉,導致系統資源的浪費,嚴重可導致系統效能減少,系統執行不穩定。
如何避免內存泄漏
總結
以上是生活随笔為你收集整理的C++ 动态内存管理:c/c++的动态内存管理,new/delete,operator new/delete,placement-new, 内存泄漏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++ 类和对象(三):构造函数补充、匿
- 下一篇: C++ 如何一次在堆上申请4G的内存?如