深度解剖~ FreeRtos閱讀筆記5 FreeRtos內存管理詳解

5  Freertos 內存管理

芯片中最爲稀缺珍貴的每每是存儲資源,爲了更好的利用它們,開發者不得不變得吝嗇分配、斤斤計較到每個字節。數組

FreeRtos V8.0.1針對動態內存分配提供了四種方案,分別放在heap一、heap二、heap三、heap4文件中。spa

 

5.1 分配方式  heap1

heap1分配方法最爲簡單,代碼量也相對較小,heap1只能申請不能回收,適合任務、隊列等不須要執行刪除操做的工程。線程

ucHeap佔據的整塊內存既爲可申請的堆空間,空間大小由configTOTAL_HEAP_SIZE定義。索引

分配以前首先對堆的起始地址作偶對齊,這有可能會使一些起始的字節做爲「佔位」而丟棄掉,最終獲得堆有效空間使用configADJUSTED_HEAP_SIZE代替。隊列

(堆初始化)內存

 

Heap1分配時使用xNextFreeByte始終記錄堆中可分配的首地址,起始值爲0。資源

若初始化後須要申請20字節:開發

(申請20字節)源碼

 

第二次申請30字節:內存管理

(申請30字節)

 

 

5.2 分配方式 heap2

Heap2中每一個內存塊都有對應結構體的記錄鏈表和塊大小,鏈表將空閒塊按照塊大小升序相連。Start和end結構體做爲索引獨立於堆區,end做爲結束標識xBlockSize老是等於堆區總大小。

Heap2初始化堆區後圖:

(heap2初始化後)

 

5.2.1 heap2申請內存

若是程序須要申請A、B、C三塊內存,須要的空間大小爲B>A>C,使用heap2的申請分配圖以下:

(申請A空間)

 

(申請B、C空間)

 

5.2.2 heap2回收內存

Heap2回收時將內存塊按照升序方式插入鏈表。假設剩餘的D空間大小等於A,程序分別釋放B、A、C內存,釋放後堆區以下:

(釋放B內存後

 

(釋放A內存後

 

(釋放C內存後

內存鏈上的內存按照塊大小遞增,記錄塊信息的結構體隨着分配逐漸增長,永遠得不到釋放。一旦程序頻繁申請小塊內存,即便釋放後也沒法申請大內存塊。

 

5.3 分配方式 heap3

Heap3使用了庫中的malloc和free,此時堆區已經脫離freertos控制,configTOTAL_HEAP_SIZE成爲無效參數。沒有源碼,,,,先不作分析~

 

5.4 分配方式 heap4

Heap4中每一個內存塊都有對應結構體的記錄鏈表和塊大小,鏈表將空閒塊按照地址升序相連。Start結構體做爲索引獨立於堆區,end屬於堆區一部分,因此去除一個結構體的size纔是堆實際分配範圍。

(heap4初始化後的堆區)

 

5.4.1 heap4申請內存

每當申請出空閒塊後都會對應產生一個新的結構體,這些結構體會佔據一部分堆空間。申請內存塊A後堆區圖:

(申請A內存後)

 

再次申請B、C內存塊:

(申請B內存後)

 

(申請C內存後)

 

5.4.2 heap4 回收內存

heap4在回收內存時會嘗試將零散的內存塊進行合併,減小碎片。

假設在申請A、B、C以後,B內存使用完畢須要釋放掉,B塊的上下都沒有相鄰的空閒內存,因此只插入空閒鏈表就能夠完成釋放。如圖:

(釋放B後)

 

釋放A時,存在相鄰的B區,兩塊內存會進行拼接,B塊的結構體也被合併,如圖:綠色區是被回收的內存

(釋放A後)

 

回收C塊時,上下都存在空閒區,回收工做分爲兩個步驟進行:

(釋放C

 

5.5 閱讀小結

相同點

除heap3外,都使用大數組做爲堆區進行分配,這看起來比較浪費,即便程序沒有申請任何空間,堆區佔據的內存在程序編譯前就已經肯定。

Heap2與heap4都須要爲記錄內存塊信息而消耗必定堆空間。

調用相同,統一使用pvPortMalloc和vPortFree,方便heap文件更換。

進行堆操做時都沒有屏蔽中斷,只是將調度器掛起。因此FreeRtos堆操做不能在中斷裏使用,若是必定要實現的話,線程中每個堆操做的地方如建立任務、信號量、隊列等~都要先屏蔽中斷,這會使FreeRtos調度器實時性降低。

 

區別

四種方式主要在分配方法上存在差別:

Heap1分配最爲簡單迅速,它適合只申請不釋放的工程。

Heap2進行頻繁申請釋放後會形成較多的碎片,適合只申請固定大小內存的工程。

Heap4像是Heap2的升級版,分配方式幾乎相同,在回收時添加了內存塊拼接以嘗試消除碎片。

相關文章
相關標籤/搜索