內存管理(1)
- 1、各類型數據在內存中的存儲空間
- 2、C++內存管理方式
- 2.1 針對于內置類型分析
- 2.2 針對于自定義類型分析
- 2.3 C語言與C++在申請動態內存失敗時的區別
- 3、operator new 和 operator delete函數(重點)
- 3.1 底層知識解析
- 3.2 實現專屬operator new 與 operator delete (了解)
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(ptr2);
}//(1) globalVar 數據段 ; staticGlobalVar 數據段; staticVar 數據段;
// localVar 棧區 ; num1 棧區
// char2(數組名\數組首元素地址) 棧區; *char2 代碼段
// pChar3(指針) 棧區; *pChar3 代碼段
// ptr1(指針) 棧區; *ptr1 堆區
//
2、C++內存管理方式
// C語言內存管理方式在C++中可以繼續使用,但有些地方就無能為力,而使用起來比較麻煩,因此C++又提出了自己的內存管理方式:通過new和delete
// 操作符進行動態內存管理。
2.1 針對于內置類型分析
void Test()
{int* p1 = (int*)malloc(sizeof(int));int* p2 = new int;//申請具有5個int的數組int* p3 = new int[5];//申請1個int的數組,并初始化為5int* p4 = new int(5);//C++11支持new[] 用{}初始化 C++98不支持//將申請具有5個int的數組 進行初始化int* p5 = new int[5]{1,2,3};free(p1);delete p2;delete[] p3;delete p4;delete[] p5;//針對內置類型,new/delete 跟 malloc/free沒有本質的區別,只有用法的區別。// new/delete 用法簡化了。
}int main()
{Test();return 0;
}
2.2 針對于自定義類型分析
class A
{
public:A(int a):_a(a){cout<<"A():"<< this << endl;}~A(){cout<< "~A():" <<this << endl;}private:int _a;
};int main()
{//堆上申請空間A* p1=(A*)malloc(sizeof(A));if (0==p1){perror("malloc fail");return 0;}//1、堆上申請空間 2、調用構造函數進行初始化A* p2 = new A; //調用默認構造函數A* p2 = new A(10); //調用非默認構造函數//申請10個A類型對象的空間,并進行初始化A* p3 = new A[5]{1,2,3,4,5};delete[] p3; //數組里的對象,先初始化后析構//釋放空間free(p1);//1、調用 析構函數 清理對象中資源 2、釋放空間delete p2;//結論: new/delete 是為自定義類型準備的;//不僅在堆上申請出來,還會調用構造函數和析構函數進行初始化和清理。//注意:new/delete new[]/delete[]一定要匹配使用,否則可能會出問題。return 0;
}
2.3 C語言與C++在申請動態內存失敗時的區別
int main()
{// malloc失敗返回NULLchar* p1 = (char*)malloc(1024u * 1024u * 1024u * 2 - 1);printf("%p\n",p1);// new失敗,不需要檢查返回值,它失敗是拋異常(異常:是面向對象語言出錯處理的方式)try{//char* p2 = new char[1024u * 1024u * 1024u*2-1];char* p2 = (char*)operator new(1024u * 1024u * 1024u);printf("%p\n", p2);operator delete(p2);}//當申請空間失敗時,才會進入catch; 若申請空間成功時,就會跳過catch;catch (const exception& e){cout<< e.what() <<endl;}return 0;
}
3、operator new 和 operator delete函數(重點)
3.1 底層知識解析
// new和delete 是用戶進行動態內存申請和釋放的操作符。operator new 和 operator delete是系統提供的全局函數,new在底層調用operator new全局函數來
// 申請空間,delete在底層通過operator delete全局函數來釋放空間。
//
// operator new全局函數——幫助new開空間——(封裝)調用malloc{ 若malloc失敗了,符合C++ new的失敗機制(失敗拋異常)}。
// operator delete全局函數——幫助delete釋放空間——(封裝)調用free
//
// new的底層分為兩部分:調用operator new + 調用構造函數; 即:new Type(自定義類型) --> call operator new【調用malloc(若開辟空間失敗,會拋異常)】 + call Type構造函數
// delete的底層也分為兩部分:調用operator delete + 調用析構函數;
//
//總結:在C++中,申請和釋放堆上的空間,就用new 和 delete
3.2 實現專屬operator new 與 operator delete (了解)
//注意:一般情況下不需要對 operator new 和 operator delete 進行重載,除非在申請和釋放空間的時候具有某些特殊的要求。比如:在使用new和delete
// 申請和釋放空間時,打印一些日志信息,來簡單幫助用戶檢測是否存在內存泄漏。
//
//當我們不寫自己專屬的operator new函數和 operator delete函數的時候,new和delete 會自動調用C++庫里面的operator new函數和 operator delete函數。
//當我們自己寫專屬的operator new函數和 operator delete函數時,new和delete 會調用專屬的operator new函數和 operator delete函數來實現某些特殊的需求。// new -> operator new + 構造函數
// 默認情況下,operator new使用全局庫里面的。
// 但每個類可以去實現自己專屬operator new; new這個類對象,它就會調用自己實現的這個operator new//實現類專屬的operator new(優先調用)
struct ListNode
{int _val;ListNode* _next;//內存池static allocator<ListNode> alloc;void* operator new(size_t n){cout<< "operator new -> STL內存池allocator申請" << endl;void* obj = alloc.allocate(1);return obj;}void operator delete(void* ptr){cout<< "operator delete -> STL內存池allocator申請" << endl;alloc.deallocate((ListNode*)ptr,1);}//構造函數struct ListNode(int val):_val(val),_next(nullptr){}
};內存池的定義
allocator<ListNode> ListNode::alloc;int main()
{//頻繁地申請 ListNode;想提高效率 —— 申請ListNode時,不去malloc,而是自己定制內存池。ListNode* node1 = new ListNode(1); //new先去調用 類里面的operator new ,如果類里面沒有operator new,就會去庫里面調用。ListNode* node2 = new ListNode(2);ListNode* node3 = new ListNode(3);delete node1;delete node2;delete node3;return 0;
}