本文由嵌入式企鵝圈原創團隊成員朱衡德(Hunter_Zhu)供稿.數組
上一篇文章中介紹了FreeRTOS多種內存管理機制中最簡單的一種:全局聲明一個靜態數組ucHeap,而後經過指針偏移記錄空間的分配狀況,在這種內存機制下沒法對內存進行釋放。同時也介紹了內存操做過程當中字節對齊的細節,本篇文章將會對FreeRTOS源碼中第二種內存管理機制heap2.c進行講解,在heap2.c中一樣使用一個全局靜態數組ucHeap來表示內存,heap2.c內存管理機制較heap1.c而言增長了內存釋放的功能,經過使用鏈表對內存進行有效管理。spa
1、BlockLink_t結構體和鏈表指針
在hesp2.c中引入了一個重要結構體:blog
BlockLink_t結構體用來描述一塊空閒空間的信息,它放在空閒塊中的前面部分,xBlockSize表示空閒塊空間的大小,空間中供程序用的大小爲:xBlockSize-sizeof(BlockLink_t)。排序
描述空閒塊信息的全部BlockLink_t結構體根據xBlockSize按小到大鏈接成鏈表。在heap2.c中,這個鏈表的開頭和結尾節點分別是xStart和xEnd,初始化時heap2.c中的鏈表結構以下:內存
初始狀態下,鏈表中只有3個節點,xStart是鏈表的頭節點;第二個節點位於內存實際有效分配空間的前面部分,這個BlockLink_t結構體描述了實際有效分配空間的信息,如這裏xBlockSize的值爲configADJUSTED_HEAP_SIZE,即初始時整塊可用空間的大小;最後一個節點爲xEnd,它的下一個節點指向NULL,xBlockSize值設置爲configADJUSTED_HEAP_SIZE是由於鏈表是按xBlockSize大小進行排序的。源碼
2、內存分配策略內存管理
heap2.c內存分配的總體思路是:空閒塊經過鏈表結構進行管理,當須要分配一塊內存時,遍歷鏈表(鏈表中的節點已經按空閒塊大小進行排序),找到第一塊夠大的空閒塊進行分配,從鏈表中移除出來,同時檢查這塊空間是否過大,若是過大就將空閒塊進行切割,而後將剩下部分從新用BlockLink_t描述並插入到鏈表中。基礎
下圖是應用程序請求分配8個字節空間後的鏈表和內存空間結構示意圖:遍歷
pvPortMalloc()核心代碼:
3、內存回收機制
heap2.c內存回收的整理思路:根據應用程序提供的空間地址,基於這個地址加上sizeof(BlockLink_t)字節偏移能夠獲得原來空閒塊的首地址,而後再將空閒塊的BlockLink_t結構體按小到大的順序插入到空閒塊鏈表中。
下面兩圖表示了程序釋放8字節空間後的鏈表和內存空間結構示意圖:
下圖展現了通過屢次內存分配和回收後的鏈表和內存空間結構示意圖:
vPortFree()核心代碼:
能夠看出,heap2.c雖然支持內存回收,可是回收內存時不進行相鄰空閒塊的合併,所以這種策略會致使內存碎片,系統運行久了會出現沒法分配過大的連續空間的狀況,heap4.c中內存管理機制就是爲了彌補這種缺陷而誕生的,它在heap2.c的基礎上增長了連續空閒塊合併的功能,下一篇會繼續進行分析。