【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