1. 程式人生 > >【c/c++】記憶體管理

【c/c++】記憶體管理

文章目錄

1.c/c++記憶體分配

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";
 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);
}

1.選擇題
選項: A.棧 B.堆 C.資料段 D.程式碼段

globalVal在哪裡?  資料段
staticGlobalVar在哪裡?資料段
staticVar在哪裡?資料段
localVar在哪裡?  棧
num1在哪裡?棧


char2在哪裡?棧
*char2在哪裡?棧
pchar3在哪裡?棧
*pchar3在哪裡?程式碼段
ptr1在哪裡?棧
*ptr1在哪裡?堆

2.填空題:

sizeof(num1) =40
sizeof(char2)=5
strlen(char2)=4
sizeof(pChar3)=4/8
strlen(pChar3)=4
sizeof(ptr1)=4/8
sizeof(ptr2)=4/8

指標的4/8與程序地址空間有關係。
指標的本質是記憶體位元組的編號。
32位malloc最大不超過3G大概就2G。
要超過3G,就換成64位。
一般棧就十幾個M。
高一G核心
低三G??(棧堆之類)
32位(2的32次方)與64位(2的64次方)跟程序有關係。
程序由編譯器控制,編譯器由人控制。

在這裡插入圖片描述

說明:

1. 棧又叫堆疊,非靜態區域性變數/函式引數/返回值等等,棧是向下增長的。
2. 記憶體對映段是高效的I/O對映方式,用於裝載一個共享的動態記憶體庫。使用者可使用系統介面建立共享共
享記憶體,做程序間通訊。(現 在只需要瞭解一下)
3. 堆用於程式執行時動態記憶體分配,堆是可以上增長的。
4. 資料段--儲存全域性資料和靜態資料。(c語言叫做靜態資料區)
5. 程式碼段--可執行的程式碼/只讀常量。(正文或常量區
不是自己的程式碼,是編譯後二進位制指令。)

2.C語言中動態記憶體管理方式malloc/calloc/realloc與free

詳細請看:https://blog.csdn.net/weixin_41892460/article/details/82666228

void Test ()
{
 int* p1 = (int*) malloc(sizeof(int));
 free(p1);

 // 1.malloc/calloc/realloc的區別是什麼?
 int* p2 = (int*)calloc(4, sizeof (int));
 int* p3 = (int*)realloc(p2, sizeof(int)*10);

 // 這裡需要free(p2)嗎?
 //不需要
 free(p3 );
}

3.C++記憶體管理方式

c語言記憶體管理在C++中可以繼續使用,但有些地方就無能為力而且使用起來比較麻煩,因此C++又提出了自己的記憶體管理方式:通過new和delete操作符進行動態記憶體管理。

3.1new/delete操作內建型別

void Test()
{
 // 動態申請一個int型別的空間
 int* ptr4 = new int;

 // 動態申請一個int型別的空間並初始化為10
 int* ptr5 = new int(10);

 // 動態申請3個int型別的空間
 int* ptr6 = new int[3];

 delete ptr4;
 delete ptr5;
 delete[] ptr6;
}

在這裡插入圖片描述
注意:申請和釋放單個元素的空間,使用new和delete操作符,申請和釋放連續的空間,使用new[]和delete[]

3.2new和delete操作自定義型別

class Test
{
public:
 Test()
 : _data(0)
 {
 cout<<"Test():"<<this<<endl;
 }
 ~Test()
 {
 cout<<"~Test():"<<this<<endl;
 }

private:
 int _data;
};
void Test2()
{
 // 申請單個Test型別的空間
 Test* p1 = (Test*)malloc(sizeof(Test));
 free(p1);

 // 申請10個Test型別的空間
 Test* p2 = (Test*)malloc(sizoef(Test) * 10);
 free(p2);
}
void Test2()
{
 // 申請單個Test型別的物件
 Test* p1 = new Test;
 delete p1;

 // 申請10個Test型別的物件
 Test* p2 = new Test[10];
 delete[] p2;
}

new:
內建內型 : malloc和new效果一樣。
自定義型別: malloc與new不一樣。
c++建議用new。
new對於自定義型別,不僅開空間並且調建構函式初始化。
而malloc只負責開空間。
注意匹配:malloc匹配free;new匹配delect。

delete:
對於內建型別,delect與free差不多;對於自定義型別,delect先析構,再釋放空間。
注意匹配:new匹配delect;malloc匹配free。

注意:
在申請自定義型別的空間時,new會呼叫建構函式,delete會呼叫解構函式,而malloc與free不會。

4.operator new與operator delete函式

new和delete是使用者進行動態記憶體申請和釋放的操作符,operator new和operator delete是系統提供的全域性變數,new在底層呼叫operator new全域性函式來申請空間,如果malloc申請空間成功就直接返回,否則執行使用者提供的空間不足應對措施,如果使用者提供該措施就繼續申請,否則就拋異常。delete在底層通過operator delete 全域性函式來釋放空間,而operator delete最終也是通過free來釋放空間的。

注意:operator new和operator delete使用者也可以自己實現,使用者實現時即可實現成全域性函式,也可實現成 類的成員函式,但是一般情況下不需要實現,除非有特殊需求。比如需要跟蹤記憶體的申請與釋放時。

5.new和delect的實現原理

5.1內建型別

如果申請的是內建型別的空間,new和malloc,delete和free基本類似,不同的是:new/delect申請和釋放的是單個元素的空間,new[]和delect[]申請的是連續空間,而且new在申請空間失敗時會拋異常,malloc會返回NULL。

5.2自定義型別

  • new的原理
    1.呼叫operator new函式申請空間
內建型別

new int  ==》 operator new開空間 ==》 malloc  ==》 構造(失敗拋異常)拋異常是為了複合c++的規範。失敗就拋異常。

malloc int ==》 malloc (失敗返回NULL)


int在c++有構造,為了相容c++。

2.在申請的空間上執行建構函式,完成物件的構造

  • delect的原理
    1.在空間上執行解構函式,完成物件中資源的清理工作
    2.呼叫operator delect函式釋放物件的空間
  • new T[N]的原理
    1.呼叫operator new[]函式,在operator new[]中實際呼叫operator new函式完成N個物件空間的申請
    2.在申請的空間上執行N次建構函式
  • delect[]的原理
    1.在釋放的物件空間上執行N次解構函式,完成N個物件中資源的清理
    2.呼叫operator delete[]釋放空間,實際在operator delect[]中呼叫operator delect來釋放空間。
內建型別

new int  ==》 operator new開空間 ==》 malloc  ==》 構造(失敗拋異常)拋異常是為了複合c++的規範。失敗就拋異常。

malloc int ==》 malloc (失敗返回NULL)


int在c++有構造,為了相容c++。

6.定位new表示式(placement-new)

定位new表示式是已分配的原始記憶體空間中呼叫建構函式初始化一個物件。
使用格式:

new (place_address) type或者new (place_address) type(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類的建構函式有引數時,此處需要傳參
}


// Test* pt = (Test*)malloc(sizeof(Test));

 new(pt) Test; 
等價於:Test* pt = new Test


7.malloc/free和new/delete的區別

malloc/free和new/delete的共同點是:都是從堆上申請空間,並且需要使用者手動釋放。不同的地方是:
1. malloc和free是函式,new和delete是操作符
2. malloc申請的空間不能初始化,new可以初始化
3. malloc申請空間時,需要手動計算空間大小並傳遞,new只需在其後跟上空間的型別即可
4. malloc的返回值為void*, 在使用時必須強轉,new不需要,因為new後跟的是空間的型別
5. malloc申請空間失敗時,返回的是NULL,因此使用時必須判空,new不需要,但是new需要捕獲異常
6. malloc/free只能申請內建型別的空間,不能申請自定義型別的空間,因為其不會呼叫構造與解構函式,
而new可以,new在申請空間後會呼叫建構函式完成物件的構造,delete在釋放空間前會呼叫解構函式
完成空間中資源的清理
7. malloc申請的空間一定在堆上,new不一定,因為operator new函式可以重新實現
因為operator new可以過載導致可能在棧上開闢
8. new/delete比malloc和free的效率稍微低點,因為new/delete的底層封裝了malloc/free