上一篇我們分享了棧內存的概念,現在我們分享下堆內存的概念。
在一般的編譯系統中,堆內存的分配方向和棧內存是相反的。當棧內存從高地址向低地址增長的時候,堆內存從低地址向高地址分配。
在C語言中,堆內存在分配和釋放的時候,是程序通過調用C語言的庫函數完成的。這和棧內存的分配有區別,棧內存利用的是處理器的硬件機制,而堆內存的處理使用的是庫函數。
我們來看下堆內存的分配情況:
在堆內存的分配過程中,每次分配將返回一個當前分配地址的指針。在程序中如果多次分配內存,可以得到多個內存指針,每個內存指針都是本次分配內存的地址。在釋放內存的時候,只需要對每個指針進行操作,那個指針所指向的內存就會被釋放,而對其他的內存區域沒有影響。
從內存的分配和使用上,可以看出棧內存和堆內存的區別:棧內存只有一個入口點,就是棧指針,棧內存壓入和彈出的時候棧指針將發生變化,棧指針標識當前棧區域中已使用和未使用的界限,程序在訪問棧內存的時候都只能通過棧指針及其偏移量;而堆內存有多個入口點,每次分配得到的指針是訪問內存的入口,每個分配內存區域都可以被單獨釋放,程序對堆內存可以通過每次分配得到的指針訪問。
堆內存有一個整體分配的過程,按照向上的堆內存分配方向。隨著堆內存使用量的增加,堆內存將逐漸向高地址分配。這只是一個大體的增長的方面,在堆內存中,已使用的區域和未使用的區域是交錯的,而不是像棧區域那樣有明顯的分界線。
堆內存的釋放看下面這個圖:
看到這樣頻繁的使用區域和釋放,那么很容易看出堆內存是不連續的,跟堆內存的使用方式有關系,這個分配就相對自由靈活了,但是也是會在低地址向高地址發展的方向分配的。
比如上面釋放后再分配就可以是下面兩種情況:
先看再次分配1的情況:當新分配的需求比中間(剛剛釋放)區域小,那么就會在緊接著的區域給分配。
再看再次分配2的情況:當新分配的需求比中間(釋放的)區域大,那么只能往后尋求能給的區域。
當頻繁的分配和釋放內存的過程中,會很容易出現在兩塊已經分配的內存之間較小的未分配內存區域,這些其實可以用,但是由于他們的空間比較小,不夠連續內存的分配,所以分配的時候就很難再次使用,這些較小的內存就是我們常說的內存碎片。
我們再來聊一下在C程序中堆空間的使用。
在C語言中,堆內存區域的分配和釋放是通過調用庫函數來完成的,實現的函數主要有四個:
void *malloc(size_t size); //分配內存空間
void free(void *ptr); //釋放內存空間
void *calloc(size_t nmemb,size_t size); //分配內存空間
void *realloc(void * ptr,size_t size); //重新分配內存空間
注意:使用上面這幾個函數需要包含標準庫文件
那么庫函數怎么使用呢,內存分配了就要有釋放,那么常用的就是malloc()和free()兩個函數。malloc()函數的輸入是需要分配內存的大小,輸出是分配內存的指針。如果分配不成功,則返回NULL。
free()函數的輸入是需要釋放的指針,可以接受任何形式的指針。這個指針必須是由分配函數分配出來的。
例如:
int *pa;
pa = (int *)malloc(sizeof(int));//分配一個int大小的指針
if(NULL != pa)
{
free(pa);
}
內存使用完成需要釋放,以便分配給其他程序使用。
calloc()也是內存分配的,只是可以把分配好的內存區域的初始值全部設置為0。還有這個分配內存有兩個參數,第一個是分配單元的大小,第二個是要分配的數目。
malloc(sizeof(unsigned int)*10); == calloc(sizeof(unsigned int),10)
realloc()有兩個參數,一個是指向內存的地址指針,一個是要重分配內存的大小,返回值是指向所分配內存的指針。
1、當參數指針為NULL的時候,作為malloc使用,分配內存。
2、當重分配內存大小為0的時候,作為free使用,釋放內存。
3、當指針和重分配內存大小均不為0的時候,根據指針指向的堆內存區域的情況和指針大小重新分配內存。
對于realloc()作為重新分配內存的時候,有三種可能出現:
1、縮小內存
2、擴大內存,不需要移動指針
3、擴大內存,需要移動指針(指定內存區域大小不夠)
在堆內存的管理上,主要容易出現以下幾個問題:
1、開辟的內存沒有釋放,造成內存泄漏(系統不會釋放任何用戶分配的內存)
2、野指針被使用或釋放(內存釋放后,需要將內存指針置為NULL)
3、非法釋放指針(分配了有效內存才存在釋放,否則是非法的)
在C語言語法的方面對棧內存和堆內存如何使用沒有限制。然后從使用的角度,棧內存更適用于容量較小的單個變量(例如:C語言的基本變量類型、較小的結構體和數組),堆內存則適用于開辟較大塊的內存。棧內存由編譯器分配和釋放,堆內存由程序員分配和釋放。
責任編輯:lq6
-
內存
+關注
關注
8文章
3115瀏覽量
75065 -
C語言
+關注
關注
180文章
7630瀏覽量
140740
原文標題:堆內存的那些事
文章出處:【微信號:gh_e7f294a514ca,微信公眾號:單片機匠人】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
如何使用LAX_CODEGEN啟用動態內存分配?
橋堆:整流電路的“中流砥柱”
養成良好的編程習慣|堆內存初值不一定是0
C語言中申請的堆內存能不能自動釋放
Windows管理內存的三種主要方式
談JVM xmx, xms等內存相關參數合理性設置
如何自定義內存控制器的設置
如何使用SystemView的堆監控功能

評論