1. 程式人生 > >FreeRTOS內存管理

FreeRTOS內存管理

kvo mtu gil ie8 策略使用 lwp fck xls vhk

heap1是FreeRTOS中內存管理最簡單的一個,它簡單到只能申請內存。是的,跟你想的一樣,一旦申請成功後,這塊內存再也無法釋放。對於大多數嵌入式系統,特別是對安全要求高的嵌入式系統,這種內存管理策略很有用,因為對系統軟件來說,邏輯越簡單,越安全。實際上,大多數的嵌入式系統並不需要動態刪除任務、信號量和隊列等。而是在初始化的時候一次性創建,便一直存在,永不刪除。 總結heap1特性如下: 1、適用於那些一旦創建好任務、信號量和隊列就再也不刪除的的應用。 2、具有可確定性(執行所花費的時間大多數一樣),而且不會導致內存碎片。 3、代碼實現和內存分配過程都非常簡單,內存是從一個靜態數組中獲取,也就是適用於那些不需要動態內存分配的應用。
我們可以將第一種內存管理看作切面包:初始化的靜態數組就像一個完整的長棍面包,每次申請內存,就從一端切下適當長度的面包返還給申請者,直到面包被分配完畢。 heap1的內存管理策略使用兩個靜態變量來跟蹤內存的使用,定義如下:
static size_t xNextFreeByte = ( size_t ) 0;
 
void *pvPortMalloc( size_t xWantedSize )
{
    static uint8_t *pucAlignedHeap = NULL;
    ...
}
其中 xNextFreeByte 用來保存 pucAlignedHeap 到內存堆剩余內存首地址之間的偏移值,如下圖所示: 技術分享圖片
變量 xNextFreeByte 一開始初始化為0,每次成功申請內存後,都會增加申請內存的大小(對齊會導致實際申請的內存更多)。 變量 pucAlignedHeap 指向每次對齊後的內存堆首地址,內存對齊的好處是硬件訪問數據只要單次讀取,而且某些類型的內核不支持非對齊訪問。STM32F0x系列的單片機要求16位對齊,非對齊讀取會導致單片機進入HardFault. 內存申請函數:pvPortMalloc
void *pvPortMalloc( size_t xWantedSize )
{
void *pvReturn = NULL;
static uint8_t *pucAlignedHeap = NULL;
 
    
/* Ensure that blocks are always aligned to the required number of bytes. */ #if(portBYTE_ALIGNMENT != 1) { if(xWantedSize & portBYTE_ALIGNMENT_MASK) { /* Byte alignment required. */ xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); } } #endif vTaskSuspendAll(); { if(pucAlignedHeap == NULL) { /* Ensure the heap starts on a correctly aligned boundary. */ pucAlignedHeap = (uint8_t *)(((portPOINTER_SIZE_TYPE)&ucHeap[portBYTE_ALIGNMENT]) & (~((portPOINTER_SIZE_TYPE) portBYTE_ALIGNMENT_MASK))); } /* Check there is enough room left for the allocation. */ if( ( ( xNextFreeByte + xWantedSize ) < configADJUSTED_HEAP_SIZE ) && ( ( xNextFreeByte + xWantedSize ) > xNextFreeByte ) )/* Check for overflow. */ { /* Return the next free byte then increment the index past this block. */ pvReturn = pucAlignedHeap + xNextFreeByte; xNextFreeByte += xWantedSize; } traceMALLOC( pvReturn, xWantedSize ); } ( void ) xTaskResumeAll(); #if( configUSE_MALLOC_FAILED_HOOK == 1 ) { if( pvReturn == NULL ) { extern void vApplicationMallocFailedHook( void ); vApplicationMallocFailedHook(); } } #endif return pvReturn; }

函數邏輯步驟: 1、xWantedSizev 根據宏 portBYTE_ALIGNMENT (實驗環境默認為4) 判斷是否要字節對齊,調整 xWantedSize 為對齊字節數的倍數。 調整方法是,找到比 xWantedSize 大, 且是最靠近 xWantedSize 的對齊數。假設 xWantedSize 是11,經過調整後,結果為12。 2、註意!內存申請的過程中禁止調度,不能被其他任務打斷。FreeRTOS 使用 vTaskSuspendAll xTaskResumeAll 禁止任務調度。 3、不僅申請的內存塊大小要求4字節對齊,內存堆的起始地址也必須是4字節對齊。pucAlignedHeapNULL的時候說明是第一次申請內存,需要初始化相關參數。ucHeap 此時的起始地址顯然不是4字節的倍數,pucAlignedHeap 不能以ucHeap 的首地址作為內存堆的首地址, pucAlignedHeap 經過調整後變為 0x0041b14c, 以3字節的損失換來了起始地址的對齊。ucHeappucAlignedHeap 第一次初始化的狀態如下圖所示: 技術分享圖片 4、進行邊界檢查,查看內存堆是否足夠本次分配,xNextFreeBytexWantedSize的和不能超出可供使用的內存邊界。如果內存夠分配且不會越界,那麽即將申請到的內存首地址賦值給pReturn 並更新全局變量 xNextFreeByte特別說明的是實際可用的內存是 configADJUSTED_HEAP_SIZE 而不是configTOTAL_HEAP_SIZE。從代碼中我們可以看出,FreeRTOS提前保留一部分字節供內存對齊使用
/* A few bytes might be lost to byte aligning the heap start address. */
#define configADJUSTED_HEAP_SIZE    ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )

技術分享圖片技術分享圖片 5、宏 configUSE_MALLOC_FAILED_HOOK 為1說明使能了內存申請失敗鉤子函數,在申請失敗的情況下,會調用鉤子函數 vApplicationMallocFailedHook ,這個鉤子函數由用戶應用程序提供,一般用來打印故障信息。 參考文章:
  • FreeRTOS內存管理分析

FreeRTOS內存管理