動態內存分配、malloc與new的區別

內存分配

先看內存的分佈狀況
這裏寫圖片描述

一個由C/C++編譯的程序佔用的內存分爲以下幾個部分:
1、棧區(stack)— 由編譯器自動分配釋放 ,存放爲運行函數而分配的局部變量、函數參數、返回數據、返回地址等。其操作方式類似於數據結構中的棧。
2、堆區(heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結束 時可能由OS回收 。分配方式類似於鏈表。
3、全局區(靜態區)(static)—存放全局變量、靜態數據、常量。程序結束後由系統釋放。
4、文字常量區 —常量字符串就是放在這裏的。 程序結束後由系統釋放。
5、程序代碼區—存放函數體(類成員函數和全局函數)的二進制代碼。

動態內存分配

在執行程序的過程中動態的分配或者回收存儲空間的分配內存的方法。

例如:當我們在定義一個數組時,必須要用一個常量來確定在編譯時分配多大的空間。但是在真正使用數組時,我們纔會知道我們需要多少內存空間,所以我們要根據程序的需要即時分配,這就牽扯到內存的動態開闢。

C語言中
malloc、calloc、realloc、free

malloc:
void *malloc(unsigned int size)
開闢一塊長度爲size的連續內存空間,返回類型爲void類型的指針。在使用malloc開闢一段空間時,void*要顯示的轉換爲所需要的類型,如果開闢失敗,則返回NULL指針。

calloc
void* calloc (size_t num, size_t size);
開闢一塊num個大小爲size的連續空間,並將每一塊空間初始化爲0。

realloc
void *realloc(void *ptr,size_t size);
將內存地址爲ptr的一段空間的大小調整爲size大小。

如果ptr這段空間後面有足夠的空間,就直接追加上來
如果ptr後面的空間不足,則在堆上重新開闢一塊合適大小的連續空間,將原有數據拷貝到新的內存空間中,釋放掉原來的內存,最後返回的則是新地址。

free
void free (void* ptr);
free函數是來釋放動態開闢的內存的。
malloc和free要配套使用,如果沒有free則會造成內存泄漏。

malloc()從哪裏獲取的內存?

動態開闢的從裏獲取空間。就是說malloc函數返回的指針是指向堆裏的一塊內存。操作系統中有一個記錄空閒內存地址的鏈表,當操作系統收到程序的申請時,就會遍歷鏈表

C++中
new、delete

new
new運算返回所分配內存單元的起始地址,所以需要把返回值保存在一個指針變量中。若分配不成功,返回NULL,並拋出異常。
new沒有爲創建的對象命名,只能通過指針去訪問對象或者數組。

delete
delete <指針變量>
delete []<動態分配的數組名>

new和delete必須配對使用。
雖然程序結束後系統會自動釋放程序和其中數據所佔的內存空間,但是爲了在程序運行過程中能夠重複使用有限的內存資源,防止系統產生內存泄漏,還是應該即時釋放不需要的動態分配的內存單元,以便系統能隨時對該內存單元進行分配。
delete釋放內存,只是銷燬內存上的對象,但是指針仍然存在,仍然指向原來的內存,保存原來空間的地址。所以我們應該在釋放之後將指針置空,以避免後面不小心解引用造成問題。

例:

int *p1 = new int;
float *p2 = new float;

char *pBuffer = new char[100];
int *pA = new int[size];
student *stu = new student[num];

int *pNum = new int(100);


delete pNum;
delete []pBuffer;

malloc 和 new的區別?

  1. malloc/free是標準庫函數,new/delete是C++運算符
  2. malloc失敗返回空,new失敗拋異常
  3. new/delete會調用構造、析構函數,malloc/free不會,所以他們無法滿足動態對象的要求。
  4. new返回有類型的指針,malloc返回無類型的指針

還有沒有其他的理解?

1.分配內存的位置
malloc是從堆上動態分配內存,new是從自由存儲區爲對象動態分配內存。
自由存儲區的位置取決於operator new的實現。自由存儲區不僅可以爲堆,還可以是靜態存儲區,這都看operator new在哪裏爲對象分配內存。

2.返回類型安全性
malloc內存分配成功後返回void*,然後再強制類型轉換爲需要的類型;new操作符分配內存成功後返回與對象類型相匹配的指針類型;因此new是符合類型安全的操作符。

3.內存分配失敗返回值
malloc內存分配失敗後返回NULL;new分配內存失敗則會拋異常(bac_alloc)。

try
{
int *a = new int();
}
catch (bad_alloc)
{
...
}

4.分配內存的大小的計算
使用new操作符申請內存分配時無須指定內存塊的大小,編譯器會根據類型信息自行計算,而malloc則需要顯式地指出所需內存的尺寸。

5.是否調用構造函數/析構函數
使用new操作符來分配對象內存時會經歷三個步驟:
- 第一步:調用operator new 函數(對於數組是operator new[])分配一塊足夠大的,原始的,未命名的內存空間以便存儲特定類型的對象。
- 第二步:編譯器運行相應的構造函數以構造對象,併爲其傳入初值。
- 第三步:對象構造完成後,返回一個指向該對象的指針。

使用delete操作符來釋放對象內存時會經歷兩個步驟:
- 第一步:調用對象的析構函數。
- 第二步:編譯器調用operator delete(或operator delete[])函數釋放內存空間。

總之來說,new/delete會調用對象的構造函數/析構函數以完成對象的構造/析構;而malloc則不會。

6.對數組的處理
C++提供了new []和delete []用來專門處理數組類型。它會調用構造函數初始化每一個數組元素,然後釋放對象時它會爲每個對象調用析構函數,但是二者一定要配套使用;至於malloc,它並不知道你要在這塊空間放置數組還是其他的東西,就只給一塊原始的空間,再給一個內存地址就完事,如果要動態開闢一個數組的內存,還需要我們手動自定數組的大小。
A * ptr = new A[10];//分配10個A對象
delete [] ptr;
int * ptr = (int *) malloc( sizeof(int) * 10);//分配一個10個int元素的數組

7.new與malloc是否可以相互調用
operator new /operator delete的實現可以基於malloc,而malloc的實現不可以去調用new

8.是否可以被重載
opeartor new /operator delete可以被重載。而malloc/free則不能重載。

9.分配內存時內存不足
malloc動態分配內存後,如果不夠用可以使用realloc函數重新分配實現內存的擴充;而new則沒有這樣的操作;

總結
將上面所述的10點差別整理成表格:

特徵 new/delete malloc/free
分配內存的位置 自由存儲區
返回類型安全性 完整類型指針 void*
內存分配失敗返回值 默認拋出異常 返回NULL
分配內存的大小 由編譯器根據類型計算得出 必須顯式指定字節數
處理數組 有處理數組的new版本new[] 需要用戶計算數組的大小後進行內存分配
已分配內存的擴充 無法直觀地處理 使用realloc簡單完成
是否相互調用 可以,看具體的operator new/delete實現 不可調用new
分配內存時內存不足 無法通過用戶代碼進行處理 能夠使用realloc函數或重新制定分配器
函數重載 允許 不允許
構造函數與析構函數 調用 不調用

delete與delete []

delete是回收new開闢出的單個對象指針指向的內存。
delete[]是回收new [] 開闢出的對象數組指針指向的內存。
new[]開闢數組空間要多出4個字節來存放數組大小。
delete []要與new []要配套使用

有了malloc/free爲什麼還要new/delete?

  1. new運算不需要進行強制類型轉換,使用簡單方便;
  2. new運算是通過調用構造函數初始化動態創建的對象,執行效率更高;
  3. 使用new能夠進行異常處理,使用更安全

需要注意的問題:

  1. 如果你在函數上面定義了一個指針變量,然後在這個函數裏申請了一塊動態分配的內存讓指針指向它。實際上,這個指針的地址是在棧上,但是它所指向的內容卻是在堆上面。這一點要注意!所以,在一個函數裏申請了空間後,比如:
void Function(void) 
{ 
      char *p = (char *)malloc(100 * sizeof(char)); 
}

千萬不要認爲函數返回,函數所在的棧被銷燬指針也跟着銷燬,申請的內存也就一樣跟着銷燬了。這是錯誤的。因爲申請的內存在堆上,除非程序員手動釋放,否則要等到程序結束釋放所有內存纔會釋放它們,跟函數是否結束沒有關係。也就是函數所在的棧被銷燬跟堆完全沒有關係。所以,忠告就是:使用完不再需要記得釋放動態分配的內存!在該部分程序退出之前釋放內存並立即給P賦0值(NULL)。另一個辦法是保證P在沒有初始化之前,將不再被使用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章