在 C++ 中,內存管理是核心課題之一。根據內存開闢的時間和方式,主要可以分為靜態內存開闢(通常涉及棧空間和全局/靜態區)和動態內存開闢(堆空間)。
1. 靜態內存開闢
靜態內存開闢是指在編譯階段就確定了大小,並在程序運行到對應作用域時由系統自動分配和釋放的內存。
- 存儲位置:主要在棧 (Stack) 或 全局/靜態存儲區。
- 分配時機:編譯時確定大小,運行時進入作用域(如函數調用)即分配。
- 管理方式:由編譯器/系統自動管理,程序員不需要手動釋放。
- 特點:分配效率極高,但空間相對有限。
示例代碼:
int a = 10; // 局部變量,在棧上開闢
static int b = 20; // 靜態變量,在全局/靜態區開闢
int arr[100]; // 數組大小必須是常量,編譯時確定
void staticlloc() {
int arr[5];
int i = 0;
for (; i < 5; i++)
{
arr[i] = i + 1;
printf("%d, %p\n", *(arr + i), arr + i);
}
}
// 重點:內存開闢
int main() {
// Stack overflow 棧溢出 , 將10 改為 0.1 才能正常運行
// int arr[(int)(10 * 1024 * 1024)]; // 棧區開闢, 10M數組大小,int四字節,40M空間
// c有分區,四驅模型,棧,堆
// 棧:佔用內存空間最大值 1M,開闢內存的方式是靜態內存開闢,方法結束會自動回收
// 堆:佔用內存空間最大值 80%,開闢內存的方式是動態內存開闢,方法結束不會自動回收,必須手動回收
staticlloc();
return 0;
}
輸出:
1, 0000009018BEFA78
2, 0000009018BEFA7C
3, 0000009018BEFA80
4, 0000009018BEFA84
5, 0000009018BEFA88
2. 動態內存開闢
動態內存開闢是指在程序運行過程中,根據實際需要申請的內存。
- 存儲位置:堆 (Heap)。
- 分配時機:運行時根據需求申請。
- 管理方式:程序員通過特定關鍵字(
new/delete)或函數(malloc/free)手動管理。 - 特點:靈活性高,可以申請非常大的空間;但如果忘記釋放,會導致內存泄漏。
示例代碼:
int* p = new int; // 在堆上申請一個 int 空間
int* arr = new int[n]; // n 可以是運行時的變量
delete p; // 必須手動釋放
delete[] arr; // 數組釋放需要加 []
C語言動態開闢方式 malloc
雖然 C++ 兼容 malloc,但在 C++ 開發中,new 幾乎在所有場景下都取代了 malloc。以下是它們的詳細對比以及為什麼 C++ 開發者更傾向於使用 new。
|
特性 |
malloc / free |
new / delete |
|
屬性 |
庫函數 (Standard Library) |
運算符 (Keyword/Operator) |
|
構造函數 |
不調用。只負責分塊內存。 |
自動調用。開闢後立即初始化對象。 |
|
返回類型 |
返回 |
返回對應類型的指針,類型安全。 |
|
計算大小 |
需手動計算字節數(如 |
編譯器根據類型自動計算大小。 |
|
內存失敗 |
分配失敗返回 |
分配失敗默認拋出異常 ( |
|
適用範圍 |
常用於 C 代碼或底層內存池開發。 |
C++ 對象的標準分配方式。 |
示例代碼:
void dynamicalloc() {
int* p = (int*)malloc(sizeof(int) * 5); // 堆區開闢
if (p == NULL) {
printf("內存開闢失敗\n");
return;
}
int i = 0;
for (; i < 5; i++)
{
*(p + i) = i + 1;
printf("%d, %p\n", *(p + i), p + i);
}
// 回收內存
free(p);
p = NULL; // 野指針
}
// 動態內存開闢
int main() {
// 堆區開闢
int* p = (int*)malloc(sizeof(int) * (10 * 1024 * 1024)); // 40M空間
if (p == NULL) {
printf("內存開闢失敗\n");
return -1;
}
// 使用內存
int i = 0;
for (; i < 10 * 1024 * 1024; i++)
{
*(p + i) = i + 1;
}
// 回收內存
free(p);
p = NULL; // 野指針
while (true) {
Sleep(100);
}
return 0;
}