1. 程式人生 > >申請與釋放記憶體的問題

申請與釋放記憶體的問題

申請記憶體空間時,申請比需求更多的空間,傳地址時,只傳遞需要的大小,當需要進行擴充套件時,再使用預留的空間。注意釋放時要整個釋放。實際上 malloc在申請記憶體時就預留了部分空間用來儲存記憶體描述資訊,返回的是與需求大小相同大小的記憶體起始地址。

在 free 的時候,我們傳遞給 malloc 返回的地址,free 通過該地址找到此塊記憶體區域的描述資訊,通過修改描述資訊就能夠完成記憶體的釋放。free(NULL) 不執行任何操作,不會造成異常。

多次 free 一個記憶體區域將會導致未定義的問題。malloc 與 calloc 一般情況下返回一個已經對齊的型別的指標。malloc 與 calloc 最大的區別在於 calloc 會將申請到的記憶體空間清0,這意味著我們呼叫 calloc 將會有額外的效能開銷。不過因此帶來的安全性完全可以挽回清 0 的效能損耗。如果我們直接呼叫 malloc ,並且未顯式清空申請到的記憶體區域,直接訪問時就可能造成嚴重的問題,畢竟此處記憶體區域的初值是不確定的呀!

free 函式並不會釋放一塊記憶體,它會將待釋放的記憶體放到空閒記憶體連結串列中,供下一次 malloc、calloc、realloc 使用。並且,相鄰的記憶體塊還以按照預設演算法進行合併,合併為一個更大的記憶體區域供程式使用。malloc 從堆中申請記憶體,可以 呼叫 sbrk 來根據需要動態調整堆的大小。

《APUE》中相關的描述如下:

儘管 sbrk 能夠擴充套件或縮減程序佔用的記憶體,大多數版本的 malloc 和 free 從來不會減少記憶體大小。我們 free 的空間一般不會返回到核心,而是被放到 malloc 管理的記憶體池中以供下一次記憶體申請使用。malloc 的大多數實現都會申請比請求大小更多的空間,並且使用額外的記憶體空間來儲存記錄資訊——如塊的大小,下一個申請塊的指標等等。因此,在申請到的塊的前後進行寫操作可能會覆蓋在其它塊中儲存的記錄資訊。這種問題很難定位,並且可能在一段時間之後才會發生,但它一旦發生就是一個大的災難。

另一個可能的錯誤是釋放一個已經釋放的記憶體或者釋放一個不是通過呼叫 malloc、realloc、calloc函式在堆中申請的記憶體。當一個程序呼叫了 malloc 卻忘記了呼叫 free 來釋放,該程序的記憶體佔用將會不斷增加,這被稱為記憶體洩露。如果我們不呼叫 free 來釋放不再使用的記憶體,程序的地址空間將會慢慢增加,直到用完所有的空閒空間為止。