1、內存分布
int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{static int staticVar = 1;int localVar = 1;int num1[10] = { 1, 2, 3, 4 };char char2[] = "abcd";const char* pChar3 = "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);
}
下面有幾個問題:
- globalvar存放在哪里? 答:數據段
- staticGlobalVal存放在哪里?答:數據段
- staticVar存放在哪里? 答:數據段
- localVar存放在哪里? 答:棧
- num1存放在哪里? 答:棧
- char2存放在哪里? 答:棧
- *char2存放在哪里? 答:棧
- pChar3存放在哪里? 答:棧
- *pChar3存放在哪里? 答:代碼段
- ptr1存放在哪里? 答:棧
- *ptr1存放在哪里? 答:堆
為什么存放在這些不同的位置呢?
C++/C內存分配有不同的位置
棧又叫堆棧:非靜態局部變量/函數參數/返回值等等,棧是向下增長的
內存映射段:這是高效的I/O映射方式,用于裝載一個動態內存庫。用戶可以使用系統接口創建共享內存,做進程間通信
堆:用于程序運行時動態內存分配,堆是可以向上增長的
數據段:存儲全局數據和靜態數據
代碼段:可執行代碼/只讀常量
2、C語言中動態內存管理方式:malloc/calloc/realloc/free
malloc:malloc有一個參數,在內存的動態存儲區中分配一塊長度為size字節的連續區域,參數size為需要的內存空間的長度,返回該區域的首地址
calloc:與malloc是相似的,只不過有兩個參數,參數一和參數二之積為所需開辟的內存空間的大小,而且這個會將開辟的空間的每一位都初始化為0
realloc:這個可以給以及分配地址的指針重新分配空間
3、C++內存管理方式
C++有了相對于C不同的內存管理方式;通過new和delete操作符來進行動態內存管理
new/delete操作內置類型
void Test()
{//動態申請一個int類的空間int* ptr4 = new int;//動態申請一個int類型的空間并且初始化為10int* ptr5 = new int(10);//動態申請10個int類型的空間int* ptr6 = new int[10];//動態申請10個int類型的空間并且初始化int* ptr7 = new int[10] {10, 9, 8, 7, 6, 5};//上面的初始化剩余沒被初始化的會被初始化0delete[] ptr6;
}
【Attention】申請和釋放單個元素的空間,使用new和delete操作符,申請和釋放連續的空間,使用new[]和delete[],注意要匹配使用
new和delete操作自定義類型
class A
{
public:A(int a = 0):_a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}
private:int _a;
};int main()
{//new/delete 和 malloc/free 最大的區別是new/delete對于[自定義類型]除了開空間還會調用構造函數和析構函數A* p1 = (A*)malloc(sizeof(A));A* p2 = new A(1);free(p1);delete p2;//內置類型幾乎是一樣的int* p3 = (int*)malloc(sizeof(int));int* p4 = new int;free(p3);delete p4;A* p5 = (A*)malloc(sizeof(A) * 10);A* p6 = new A[10];free(p5);delete[] p6;return 0;
}
注意:在申請自定義類型的空間時,new會調用構造函數,delete會調用析構函數,而malloc與free不會
4、operator new 與 operator delete函數(重點)
operator new 和 operator delete 函數
new和delete是用戶進行動態內存申請和釋放的操作符,operator new 和 operator delete 是系統提供的全局函數,new在底層調用operator new全局函數來申請空間,delete在底層通過operator delete全局函數來釋放空間?
int main()
{Stack* ps2 = (Stack*)operator new (sizeof(Stack));operator delete(ps2);Stack* ps1 = (Stack*)malloc(sizeof(Stack));assert(ps1);free(ps1);
}
operator new實際是通過malloc來申請空間,如果malloc申請空間成功則直接返回,否則執行用戶提供的空間不足應對措施,如果用戶提供該措施就繼續申請,否則就拋異常。operator delete最終就是通過free來申請空間的
5、new和delete的實現原理
內置類型
如果申請的是內置類型的空間,new和malloc,delete和free基本類型,不同的地方是:new/delete申請和釋放的是單個元素的空間,new[]和delete[]申請和釋放的是連續空間,而且new在申請空間失敗時會拋異常,malloc會返回NULL
自定義類型
- new的原理:1、調用operator new函數申請空間? ?2、在申請的空間上執行構造函數,完成對對象的構造
- delete的原理:1、在空間上執行析構函數,完成對象中資源的清理工作? 2、調用operator delete函數釋放對象的空間
- new T[N]的原理:1、調用operator new[]函數,在operator new[]中實際調用operator new函數完成N個對象空間的申請? 2、在申請的空間上執行N次構造函數
- delete[]的原理:1、在釋放的對象空間上執行N次析構函數,完成對N個對象中資源的清理? 2、調用operator delete[]釋放空間,實際在operator delete[]中調用operator delete來釋放空間
6、定位new表達式(placement-new)
定位new表達式是在已分配的原始內存空間中調用構造函數初始化一個對象
使用格式:
new(place_address)type 或者 new(place_address) type(initializer-list)
place_address必須是一個指針,initializer-list是典型的初始化列表
class A
{
public:A(int a = 0):_a(a){cout << "A():" << this << endl;}~A(){cout << "~A()" << this << endl;}
private:int _a;
};//定位new/replacement new
int main()
{//p1現在指向的只不過是與A對象相同大小的空間,還不能算是一個對象,因為構造函數沒有執行A* p1 = (A*)malloc(sizeof(A));new(p1)A;//注意:如果A類的構造函數有參數時,此時需要傳參p1->~A();free(p1);A* p2 = (A*)operator new(sizeof(A));new(p2)A(10);p2->~A();operator delete(p2);return 0;
}
7、常見面試題
malloc/free和new/delete的區別
相同點:malloc/free和new/delete的共同點是:都是從堆上申請空間,而且需要用戶手動釋放
不同點:
- malloc和free是函數,new和delete是操作符
- malloc申請的空間不會初始化,new可以初始化
- malloc申請空間時,需要手動計算空間大小并且傳遞,new只需在其后面更上空間類型即可,如果是多個對象,[]中指定對象個數即可
- malloc的返回值是void*,在使用時必須強轉,new則不需要,因為new后跟的是空間的類型
- malloc申請空間失敗時,返回的是NULL,使用時必須判空,new則不需要,但是new需要捕獲異常
- 申請自定義類型對象時,malloc/free只會開辟空間,不會調用構造函數和析構函數,而new在申請空間后會調用構造函數完成對象初始化,delete在釋放空間前會調用析構函數完成空間中資源的清理
什么是內存泄露,內存泄露的危害
什么是內存泄露:內存泄露指因為疏忽或走錯屋造成程序未能釋放已經不再使用內存的情況。內存泄露并不是指內存在物理上的消失,而是應用程序分配某段內存后,因為設計錯誤,失去了對該段內存的控制,因而造成了內存的浪費
內存泄露的危害:長期運行的程序出現內存泄露,影響很大,如操作系統、后臺服務,出現內存泄露會導致相應越來越慢,最終卡死
內存泄露的分類
堆內存泄露:
堆內存泄露是指程序執行中依據需要分配通過malloc/calloc/realloc/new等從堆中分配的一塊內存,用完后必須通過調用相應的free或者delete刪掉。假設程序的設計錯誤導致這部分內存沒有釋放,那么以后這部分空間將無法再被使用,就會產生Heap Leak
系統資源泄露:
指程序使用系統分配的資源,比如套接字、文件描述符、管道等沒有使用對應的函數釋放掉,導致系統資源的浪費,嚴重可導致系統效能的減少,系統執行不穩定