C C 記憶體管理詳情

2022-09-28 01:42:11 字數 3265 閱讀 5821

目錄

記憶體管理是c++最令人切齒痛恨的問題,也是c++最有爭議的問題,c++高手從中獲得了更好的效能,更大的自由,c++菜鳥的收穫則是一遍一遍的檢查**和對c++的痛恨,但記憶體管理在c++中無處不在,記憶體洩漏幾乎在每個c++程式中都會發生,因此要想成為c++高手,記憶體管理一關是必須要過的,除非放棄c++,轉到j**a或者.net,他們的記憶體管理基本是自動的,當然你也放棄了自由和對記憶體的支配權,還放棄了c++超絕的效能。

程式設計師們經常編寫記憶體管理程式,往往提心吊膽。如果不想觸雷,唯一的解決辦法就是發現所有潛伏的地雷並且排除它們,躲是躲不了的。

在c++中,記憶體分成5個區,他們分別是堆、棧、自由儲存區、全域性/靜態儲存區和常量儲存區。

明確區分堆與棧

堆與棧的區分問題,似乎是乙個永恆的話題,由此可見,初學者對此往往是混淆不清的,所以我決定拿他第乙個開刀。 

首先,我們舉乙個例子

void f()

這條短短的一句話就包含了堆與棧,看到new,我們首先就應該想到,我們分配了一塊堆記憶體,那麼指標p呢?他分配的是一塊棧記憶體,所以這句話的意思就是:在棧記憶體中存放了乙個指向一塊堆記憶體的指標p。在程式會先確定在堆中分配記憶體的大小,然後呼叫operatwww.cppcns.comor new分配記憶體,然後返回這塊記憶體的首位址,放入棧中。

這裡,我們為了簡單並沒有釋放記憶體,那麼該怎麼去釋放呢?是delete p麼?澳,錯了,應該是delete [ ]p,這是為了告訴編譯器:我刪除的是乙個陣列,編譯器就會根據相應的cookie資訊去進行釋放記憶體的工作。

void test ()

2.1 malloc/calloc/realloc和free

malloc

malloc程式設計客棧分配的記憶體是位於堆中的,並且沒有初始化記憶體的內容,因此基本上malloc之後,呼叫函式memset來初始化這部分的記憶體空間.

void* malloc (size_t size);

size_t是unsigned int。

malloc:分配一塊size byte大小的記憶體空間,返回乙個指向該塊記憶體開始的指標,指標的型別是void

函式malloc不能初始化所分配的記憶體空間,而函式calloc能.如果由malloc()函式分配的記憶體空間原來沒有被使用過,則其中的每一位可能都是0;反之, 如果這部分記憶體曾經被分配過,則其中可能遺留有各種各樣的資料.也就是說,使用malloc()函式的程式開始時(記憶體空間還沒有被重新分配)能正常進行,但經過一段時間(記憶體空間還已經被重新分配)可能會出現問題.

realloc

realloc則對malloc申請的記憶體進行大小的調整.

void* realloc (void* ptr, size_t size);

realloc可以對給定的指標所指的空間進行擴大或者縮小,無論是擴張或是縮小,原有記憶體的中內容將保持不變.當然,對於縮小,則被縮小的那一部分的內容會丟失.realloc並不保證調整後的記憶體空間和原來的記憶體空間保持同一記憶體位址.相反,realloc返回的指標很可能指向乙個新的位址.

realloc是從堆上分配記憶體的.當擴大一塊記憶體空間時,realloc()試圖直接從堆上現存的資料後面的那些位元組中獲得附加的位元組,如果能夠滿足,自然天下太平;如果資料後面的位元組不夠,問題就出來了,那麼就使用堆上第乙個有足夠大小的自由塊,現存的資料然後就被拷貝至新的位置,而老塊則放回到堆上.這句話傳遞的乙個重要的資訊就是資料可能被移動.

calloc

為乙個大小為num的陣列分配記憶體,每個元素的大小是size,把每個元素初始化為0。

void* calloc(size_t numelements, size_t sizeofelement);

函式calloc() 會將所分配的記憶體空間中的每一位都初始化為零,也就是說,如果你是為字元型別或整數型別的元素分配記憶體,那麼這些元素將保證會被初始化為0;如果你是為指標型別的元素分配記憶體,那麼這些元素通常會被初始化為空指標;如果你為實型資料分配記憶體,則這些元素會被初始化為浮點型的零.

3.1 new/delete操作內建型別

int *i = new int; //沒有初始值

int *j = new int(100); //初始值為100

int *iarr = new int[3]; //分配具有3個元素的陣列

delete i; //釋放單個變數所占用的記憶體

delete j;

delete iarr; //釋放陣列所占用的記憶體

3.2 new和delete操作自定義型別

class test

~test()

private:

int _data;

};void test2()

void test2()

從上例可看出,new呼叫了類test的建構函式,而malloc只是分配了空間,並沒有呼叫建構函式,因此會出現呼叫test2函式時,輸出的結果具有隨機性。如果用free釋放「new建立的動態物件」,那麼該物件因無法執行析構函式而可能導致程式出錯。如果用delete釋放「malloc申請的動態記憶體」,理論上講程式不會出錯,但是該程式的可讀性很差。所以new/delete必須配對使用,malloc/free也一樣。

上例中,test為類的析構函式,物件離開作用域或被delete的時候會呼叫。指標p指向了乙個堆上建立的test物件,若用free來釋放記憶體,則不會呼叫析構函式

new和delete操作符,operator new和operator delete是系統提供的全域性函式,new在底層呼叫operator new全域性函式來申請空間,delete在底層通過operator delete全域性

函式來釋放空間

void *__crtdecl operator new(size_t size) _throw1(_std bad_alloc)

return (p);

}operator new是通過malloc來申請空間,如果malloc申請空間成功就直接返回,否則返回null,如果使用者提供該措施就繼續申請,否則就拋異常。operator delete是通過free來釋放空間的

5.1、new

new操作針對資料型別的處理,分為兩種情況:

(1) 簡單資料型別(包括基本資料型別和不需要建構函式的型別)

(2)複雜資料型別(需要由建構函式初始化物件) 

new 複雜資料型別的時候先呼叫operator new,然後在分配的記憶體上呼叫建構函式。

5.2、delete

delete也分為兩種情況:

5.3、new 陣列

new也分為兩種情況:

5.4、delete 陣列

delete也分為兩種情況:

C C 之記憶體對齊詳情

計算機系統對基本型別資料在記憶體中放的位置做了限制,它們會要求這些數的首位址是乙個數 一般為4和8 的整數倍,我們看下結構體的大小 include struct a int main 結果 1111demacbook pro digui a1111 sizeof size of struct a i...

c c 記憶體管理

我一直覺得記憶體是很複雜的東西.也許我把這篇文章完成的時候,我會了解一點c 的記憶體管理機制 從硬體開始 記憶體器位址空間 匯流排位址空間 cpu位址空間 虛擬記憶體位址空間 程式位址空間 邏輯位址空間 程式位址空間對c 程式設計師來說是可見的,其他位址空間我們並不關心 通過列印pointer的值 ...

C C 記憶體管理

寫乙個好的c 程式,我們要懂得好多東西,比如說最基本的物件導向程式設計思想,c 的封裝 繼承 多型機制,設計模式等,還有乙個很重要的內容便是效能優化,像c c 這種接近底層的語言,追求的就是效能,與之相關的一項內容便是記憶體管理,記憶體分配要合理,禁止破壞記憶體,不能有記憶體洩漏,操作不好的話,程式...