C和C++的動態記憶體管理的區別
這裡寫目錄標題
前言
C++是一個極度追求效能的語言,因此在所有語言之中,對於記憶體過分執著“較真”,這也就產生了記憶體管理!
1.C/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);
}
通過這段程式碼,來考驗考驗我們的C語言記憶體管理問題:
選擇題:
選項: A.棧 B.堆 C.資料段 D.程式碼段
globalVar在哪裡?C staticGlobalVar在哪裡?_C
staticVar在哪裡?C localVar在哪裡?A
num1 在哪裡?A
char2在哪裡?A *char2在哪裡?A
pChar3在哪裡?A *pChar3在哪裡?D
ptr1在哪裡?A *ptr1在哪裡?B
1.棧又被稱之為堆疊,非靜態區域性變數/函式引數/返回值等等都存放在棧之中。
2.記憶體對映段是高效的I/O對映方式,用於裝載一個共享的動態記憶體庫,可使用系統介面建立共享記憶體,做程式間通訊。
3.堆用域程式執行時動態記憶體的分配。
4.資料段是儲存全域性資料和靜態資料的。
5.程式碼段是放置可執行的程式碼和只讀常量。
2. C/C++語言動態記憶體管理方式
2.1C語言動態記憶體管理方式
malloc/calloc/realloc/free
是我們C語言中經常使用到的動態記憶體管理,
1.普通的陣列空間申請
void test1()
{
int array[10]; //都為隨機值
int array2[10] = { 1, 2, 3 }; //除過前三個,其它都為0
int array3[10] = { 0 }; //所有位置都為0
}
2. malloc和calloc以及realloc的空間管理
void test2()
{
//malloc:只進行空間申請,不進行初始化
int* ptr = (int*)malloc(sizeof(int));
*ptr = 4;
//calloc: 進行空間申請 + 零初始化
int* ptr2 = (int*)calloc(1, sizeof(int));
//realloc: 第一個引數為nullptr/NULL, 功能等價於malloc
int* ptr3 = (int*)realloc(nullptr, sizeof(int));
//調整空間大小:
// 1. 直接原地調整大小
// 2. 重新開空間: 重新申請空間,內容拷貝,釋放原有空間
int* ptr4 = (int*)realloc(ptr, sizeof(int) * 4);
char* ptr5 = (char*)realloc(ptr2, sizeof(char));
free(ptr3);
free(ptr4);
free(ptr5);
//傳入realloc中的空間後續不需要顯式釋放,會導致二次釋放的問題
/*free(ptr);
free(ptr2);*/
}
2.或者realloc
2.2C++動態記憶體管理方式
雖然C語言的記憶體管理方式在C++中可以繼續使用,但是有些地方不僅無能為力而且使用起來還會有很多缺點,因此C++也是提出了適合自己的記憶體管理方式,那就是new和delete操作符來進行動態記憶體管理。
void test1()
{
// 單個型別的空間:new + 型別
// 連續空間:new + 型別[個數]
// 單個型別空間申請 + 初始化: new + 型別(初始值)
// 基本型別用new申請連續空間,不能初始化
int* ptr3 = new int;
int* ptr4 = new int[10];
int* ptr5 = new int(5); //初始化為5
//釋放空間
//單個空間: delete 指標
//連續空間: delete[] 指標
//申請和釋放的操作匹配使用: malloc free, new delete, new [] delete[]
delete ptr3;
delete ptr5;
delete[] ptr4;
}
class Date{
public:
Date(){
}
}
void test2()
{
//動態建立自定義型別的物件:
//new:動態開空間 + 呼叫建構函式初始化
//申請單個空間: new 自定義型別(引數列表)
Date* pd = new Date(2020);
Date* pd2 = new Date(2030);
Date* pd4 = new Date; //呼叫預設構造:無參,全預設
//申請連續的空間:new 自定義型別[個數], 自動呼叫預設構造進行初始化,如果沒有預設構造,編譯器報錯
Date* pd3 = new Date[10];
//釋放自定義型別的空間
//delete: 呼叫解構函式清理資源 + 釋放空間
delete pd;
delete pd2;
delete pd4;
//連續空間: 呼叫N次析構 + 釋放空間
delete[] pd3;
}
區別:在申請自定義型別的空間時:new會呼叫建構函式,而delete會呼叫解構函式,而malloc和free不會。
3. operator new和operator delete
operator new和operator delete這兩者是系統所提供的全域性函式,new會在底層呼叫operator new來申請空間,delete會在底層呼叫operator delete來釋放空間,而在operator new和operator delete 實現中我們可以發現還是通過malloc來進行申請,通過free來進行釋放。
void test()
{
//void* operator new(size_t n): 不是運算子過載函式,而是一個全域性函式
// : 使用方式和malloc類似
// : 封裝malloc + 異常
//new 10;
//new的執行過程(自定義型別):operator new --> malloc --> 建構函式
char* ptr = (char*) operator new(sizeof(char));
char* ptr2 = (char*)malloc(sizeof(char));
//void operator delete(void* ptr):不是運算子過載函式,而是一個全域性函式
// :使用方式和free類似
// :封裝free
// delete執行過程(自定義型別): 析構 --> operator delete --> free
operator delete(ptr);
free(ptr2);
free(nullptr);
operator delete(nullptr);
}
4.new和delete的實現原理
5new的表示式
void test()
{
//new定位表示式,給予申請的空間進行初始化
Date* pd = (Date*)malloc(sizeof(Date));
//new定位表示式: new (地址) 型別(引數列表)
// :在已經開好的空間上顯式呼叫建構函式
new (pd)Date(2030);
Date* pd2 = (Date*)malloc(sizeof(Date));
new (pd2)Date;
}
6面試題
1.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在釋放空間前會呼叫解構函式完成空間中資源的清理
2,什麼是記憶體洩漏,記憶體洩漏的危害,如何避免記憶體洩漏
什麼是記憶體洩漏:記憶體洩漏指因為疏忽或錯誤造成程式未能釋放已經不再使用的記憶體的情況。記憶體洩漏並不是指記憶體在物理上的消失,而是應用程式分配某段記憶體後,因為設計錯誤,失去了對該段記憶體的控制,因而造成了記憶體的浪費。
記憶體洩漏的危害:長期執行的程式出現記憶體洩漏,影響很大,如作業系統、後臺服務等等,出現記憶體洩漏會導致響應越來越慢,最終卡死。
避免記憶體洩漏:實現防禦如智慧指標;時候差錯如洩漏檢測工具。
void MemoryLeaks()
{
// 1.記憶體申請了忘記釋放
int* p1 = (int*)malloc(sizeof(int));
int* p2 = new int;
// 2.異常安全問題
int* p3 = new int[10];
Func(); // 這裡Func函式拋異常導致 delete[] p3未執行,p3沒被釋放.
delete[] p3;
}
相關文章
- C++動態記憶體管理——new/deleteC++記憶體delete
- C++動態記憶體分配C++記憶體
- c++動態記憶體管理與智慧指標C++記憶體指標
- C++動態記憶體管理與原始碼剖析C++記憶體原始碼
- C++記憶體管理C++記憶體
- 【C/C++】4.C++的記憶體管理C++記憶體
- C++ 指標動態記憶體分配C++指標記憶體
- C語言之動態記憶體管理C語言記憶體
- C++記憶體管理:new / delete 和 cookieC++記憶體deleteCookie
- C++記憶體管理剖析C++記憶體
- C++記憶體管理:簡易記憶體池的實現C++記憶體
- C++ 動態記憶體分配與名稱空間C++記憶體
- C++基礎-1-記憶體管理(全域性區、堆區、棧區)C++記憶體
- java記憶體溢位和記憶體洩漏的區別Java記憶體溢位
- c++動態記憶體智慧指標及weak_ptr用法的理解C++記憶體指標
- 【C++】 外傳篇 3_動態記憶體申請的結果C++記憶體
- C和C++區別C++
- 【知識分享】伺服器記憶體和普通記憶體的區別伺服器記憶體
- 靜態方法和普通的成員方法||分配記憶體空間的區別記憶體
- C/C++程式除錯和記憶體檢測C++除錯記憶體
- 記憶體跟硬碟的區別記憶體硬碟
- C++ - 二級指標動態記憶體申請與釋放C++指標記憶體
- C++中的return和exit區別C++
- c++中指標和引用的區別?C++指標
- 請描述C/C++程式的記憶體分割槽?C++記憶體
- 記憶體分配策略中,堆和棧的區別記憶體
- C++記憶體掃描C++記憶體
- c與c++的區別C++
- C/C++引用和指標的聯絡和區別C++指標
- C++中break和continue的用法和區別C++
- 關於java的引用和c++的區別JavaC++
- C++ Primer plus 第12章類和動態記憶體分配複習題參考答案C++記憶體
- 記憶體管理篇——實體記憶體的管理記憶體
- linux記憶體管理(一)實體記憶體的組織和記憶體分配Linux記憶體
- C++手寫記憶體池C++記憶體
- Java的記憶體管理機制之記憶體區域劃分Java記憶體
- C/C++記憶體分配以及釋放C++記憶體
- C/C++記憶體對齊原則C++記憶體