在使用 FreeRTOS 創建任務、隊列、信號量等對象時,通常都有動態創建和靜態創建的方式。動態方式提供了更靈活的內存管理,而靜態方式則更注重內存的靜態分配和控制。
如果是1·的,那么標準 C 庫 malloc() 和 free() 函數有時可用于此目的,但是有以下缺點:
它們在嵌入式系統上并不總是可用。
它們占用了寶貴的代碼空間。
它們不是線程安全的。
它們不是確定性的 (執行函數所需時間將因調用而異)。
所以更多的時候需要的不是一個替代的內存分配實現。一個嵌入式/實時系統的 RAM 和定時要求可能與另一個非常不同,所以單一的 RAM 分配算法將永遠只適用于一個應用程序子集。為了避免此問題,FreeRTOS 將內存分配 API 保留在其可移植層,提供了五種內存管理算法:?
heap_1:最簡單,不允許釋放內存。
heap_2:允許釋放內存,但不會合并相鄰的空閑塊。
heap_3:簡單包裝了標準 malloc() 和 free(),以保證線程安全。
heap_4:合并相鄰的空閑塊以避免碎片化。包含絕對地址放置選項。
heap_5:如同 heap_4,能夠跨越多個不相鄰內存區域的堆。
FreeRTOS內存管理算法
heap_1算法
heap_1 是最簡單的實現方式。內存一經分配,它不允許內存再被釋放。盡管如此,heap_1.c 還是適用于大量嵌入式應用程序。這是因為許多小型和深度嵌入的應用程序在系統啟動時創建了所需的所有任務、隊列、信號量等,并在程序的生命周期內使用所有這些對象(直到應用程序再次關閉或重新啟動)。任何內容都不會被刪除。
heap_2算法
heap_2 使用最佳適應算法,并且與方案 1 不同,它允許釋放先前分配的塊,它不將相鄰的空閑塊組合成一個大塊。------空閑塊不會合并
heap_2.c 適用于許多必須動態創建對象的小型實時系統 。
1、如果動態地創建和刪除任務,且分配給正在創建任務的堆棧大小總是相同的,那么 heap2.c 可以在大多數情況下使用。
2、但是,如果分配給正在創建任務的堆棧的大小不是總相同,那么可用的空閑內存可能會被碎片化成許多小塊,最終導致分配失敗。
heap_2 使用最佳適應算法,該算法在空閑內存中選擇與請求的內存大小最接近的塊來分配內存。下面是一個簡單的例子來說明最佳適應算法:
假設有一個空閑內存,其中包含以下塊:
大小為 20 字節的空閑塊。
大小為 15 字節的空閑塊。
大小為 25 字節的空閑塊。
現在有一個任務請求分配 18 字節的內存。最佳適應算法將選擇大小為 20 字節的塊,因為它與請求的大小最接近。在選擇這個塊后,分配器可能會將該塊分割為兩部分,一部分大小為 18 字節,用于任務的內存,另一部分大小為 2 字節,留作未分配的塊。
heap_3算法
heap_3使用 C 庫的 malloc 和 free 函數來進行內存分配和釋放。它通過分配固定大小的塊來管理內存,這些塊的大小在配置 FreeRTOS 時進行定義,不會動態改變。
假設我們使用 Heap_3 管理內存,其中塊的大小固定為 32 字節。初始時,整個內存被分割成大小為 32 字節的塊:
塊 1(32 字節)。
塊 2(32 字節)。
塊 3(32 字節)。
現在,有一個任務請求分配 20 字節的內存。Heap_3 算法將選擇塊 1,并將其分割成兩部分:
分配給任務的內存塊(20 字節)。
剩余未分配的塊(12 字節)。
再假設另一個任務請求分配 40 字節的內存。由于沒有足夠大的塊可供分配,heap_3 將返回分配失敗的狀態。
heap_3 的特點是塊大小固定,這樣可以簡化內存管理。然而,也因為塊大小不可變,可能導致內存碎片問題,即一些塊可能無法完全被利用,從而浪費了一些內存。
heap_4算法
heap_4使用第一適應算法,并且會將相鄰的空閑內存塊合并成大內存塊,減少內存碎片。
第一適應算法會在可用內存塊中選擇第一個足夠大的內存塊進行分配。
假設有一個內存塊鏈表,其中包含以下順序的內存塊:
大小為 40 字節的塊。
大小為 30 字節的塊。
大小為 15 字節的塊。
大小為 20 字節的塊。
如果一個任務需要申請 25 字節的內存,第一適應算法將選擇大小為 40 字節的塊,因為它是第一個足夠大以容納任務需求的內存塊。(如果是heap_2的最佳適應算法,會選擇30字節的塊)
heap_5算法
heap_5使用與 heap_4 相同的第一適應和內存合并算法,允許堆跨越多個不相鄰(非連續)內存區域。適用于內存地址不連續的復雜場景。
reeRTOS內存管理相關API函數介紹
內存管理相關函數如下:
函數 | 描述 |
void * pvPortMalloc( size_t ?xWantedSize ); | 申請內存 |
void ?vPortFree( void * pv ); | 釋放內存 |
size_t ?xPortGetFreeHeapSize( void ); | 獲取當前空閑內存的大小 |