1.前言
不同的嵌入式系統具有不同的內存配置和時間要求。所以單一的內存分配算法只可能適合部分應用程序。
FreeRTOS 將內存分配作為可移植層面(相對於基本的內核代碼部分而言)。這使得不同的應用程序可以提供適合自身的具體實現。
本章期望讓讀者了解以下事情:
- FreeRTOS 在什么時候分配內存。
- FreeRTOS 提供的三種內存分配方案范例
2.FreeRTOS內存管理概述
(1)當內核請求內存時,其調用pvPortMalloc()而不是直接調用malloc();當釋放內存時,調用vPortFree()而不是直接調用free()。
pvPortMalloc()具有與malloc()相同的函數原型;vPortFree()也具有與free()相同的函數原型。
(2)FreeRTOS 自帶有三種pvPortMalloc()與vPortFree()實現范例.FreeRTOS 的用戶可以選用其中一種,也可以采用自己的內存管理方式
這三個范例對應三個源文件:heap_1.c,heap_2.c,heap_3.c——這三個文件都放在目錄FreeRTOS\Source\Portable\MemMang 中
(3)早期版本的FreeRTOS 所采用的原始內存池和內存塊分配方案已經被移除了,因為定義內存塊和內存池的大小需要較深入的努力和理解。
(4)選擇內存分配方案時不必考慮一些復雜的因素,比如確定性與內存碎片等,而只需要從性能上考慮,比如代碼大小和簡易性
在小型嵌入式系統中,通常是在啟動調度器之前創建任務,隊列和信號量。
這種情況表明,動態分配內存只會出現在應用程序真正開始執行實時功能之前,而且內存一旦分配就不會再釋放
3. 內存分配方案范例
3.1 heap_1.c原理說明
(1)Heap_1.c 實現了一個非常基本的pvPortMalloc()版本,而且沒有實現vPortFree()
如果應用程序不需要刪除任務,隊列或者信號量,則具有使用heap_1 的潛質
(2)這種分配方案是將FreeRTOS 的內存堆空間看作一個簡單的數組。
當調用pvPortMalloc()時,則將數組又簡單地細分為更小的內存塊。
(3)數組的總大小(字節為單位)在FreeRTOSConfig.h 中由configTOTAL_HEAP_SIZE定義。
以這種方式定義一個巨型數組會讓整個應用程序看起來耗費了許多內存——即使是在數組沒有進行任何實際分配之前。
(4)需要為每個創建的任務在堆空間上分配一個任務控制塊(TCB)和一個棧空間
3.2 heap_1.c內存分配示例

(1)A 表示數組在沒有任何任務創建時的情形,這里整個數據是空的。
(2)B 表示數組在創建了一個任務后的情形。
(3)C 表示數組在創建了三個任務后的情形。
3.3 heap_2.c原理說明
(1)Heap_2.c 也是使用了一個由configTOTAL_HEAP_SIZE 定義大小的簡單數組
(2)不同於heap_1 的是,heap_2 采用了一個最佳匹配算法來分配內存,並且支持內存釋放
(3)由於聲明了一個靜態數組,所以會讓整個應用程序看起來耗費了許多內存——即使是在數組沒有進行任何實際分配之前
(4)最佳匹配算法保證pvPortMalloc()會使用最接近請求大小的空閑內存塊
舉例:堆空間中包含了三個空閑內存塊,分別為5 字節,25 字節和100 字節大小。pvPortMalloc()被調用以請求分配20 字節大小的內存空間。
匹配請求字節數的最小空閑內存塊是具有25字節大小的內存塊——所以pvPortMalloc()會將這個25 字節塊再分為一個20 字節塊和一個5 字節塊3,然后返回一個指向20 字節塊的指針。
剩下的5 字節塊則保留下來,留待以后調用pvPortMalloc()時使用
(5)Heap_2.c 並不會把相鄰的空閑塊合並成一個更大的內存塊,所以會產生內存碎片——如果分配和釋放的總是相同大小的內存塊,則內存碎片就不會成為一個問題
(6)Heap_2.c 適合用於那些重復創建與刪除具有相同棧空間任務的應用程序
3.4 heap_2.c內存分配示例

上圖展示了當任務創建,刪除以及再創建過程中,最佳匹配算法是如何工作的
(1)A 表示數組在創建了三個任務后的情形。數組的頂部還剩余一個大空閑塊。
(2) B 表示數組在刪除了一個任務后的情形。頂部的大空閑塊保持不變,並多出了兩個小的空閑塊,分別是被刪除任務的TCB 和任務棧。
(3) C 表示數組在又創建了一個任務后的情形。創建一個任務會產生兩次調用pvPortMalloc(),一次是分配TCB,一次是分配任務棧
注:(1)調用pvPortMalloc()發生在xTaskCreate() API 函數內部
(2)每個TCB 都具有相同大小,所以最佳匹配算法可以確保之前被刪除的任務占用的TCB 空間被重新分配用作新任務的TCB 空間。
(3)新建任務的棧空間與之前被刪除任務的棧空間大小相同,所以最佳匹配算法會保證之前被刪除任務占用的棧空間會被重新分配用作新任務的棧空間。數組頂部的大空閑塊依然保持不變。
(4)Heap_2.c 雖然不具備確定性,但是比大多數標准庫實現的malloc()與free()更有效率
3.5 heap_3.c原理說明
(1)Heap_3.c 簡單地調用了標准庫函數malloc()和free(),但是通過暫時掛起調度器使得函數調用具備線程安全特性
(2)內存堆空間大小不受configTOTAL_HEAP_SIZE 影響,而是由鏈接器配置
3.6 heap_3.c內存分配舉例
4.參考文獻
[1]FreeRTOS中文實用教程
