FreeRTOS程式碼閱讀筆記:heap_1.c
阿新 • • 發佈:2018-10-31
FreeRTOS中對於記憶體的管理當前一共有5種實現方式(作者當前的版本是10.1.1),均在【 \Source\portable\MemMang 】下面,這裡筆記下。
重要的引數:
使用方法: 標頭檔案:FreeRTOSConfig.h 配置引數: configTOTAL_HEAP_SIZE 定義系統所用的堆疊大小。 configUSE_MALLOC_FAILED_HOOK 預設0: 1則開啟鉤子函式,記憶體分配失敗則呼叫 函式呼叫: vPortInitialiseBlocks();//初始化 ptr=pvPortMalloc(1024); if(ptr !=NULL) { freemem=xPortGetFreeHeapSize(); printf("剩餘記憶體 %d \r\n",i,freemem); } else { printf("獲取記憶體失敗\r\n");break; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
heap_1.c分析:
/************************************** 重要的引數備註: (1)FreeRTOS 記憶體堆為:ucHeap[] 大小為 configTOTAL_HEAP_SIZE (2)pucAlignedHeap 作為堆疊位元組對齊後的起始地址(怎麼實現的思考一下) pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ])& ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); (3)configADJUSTED_HEAP_SIZE 堆疊可操作空間,減去對齊單位,防止越界 #define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT ) 保證pucAlignedHeap也是在按照指定記憶體要求對齊的,通過這裡可以知道,初始化pucAlignedHeap時並不是一定等於&ucHeap[0]的,而是會根據位元組對齊的要求,在&ucHeap[0]和&ucHeap[portBYTE_ALIGNMENT]之間,這就會導致ucHeap的前幾個位元組可能會被浪費到,這也是為什麼會有一個configADJUSTED_HEAP_SIZE (4)xNextFreeByte 記錄已經使用的記憶體數量 舉個例子: 假設記憶體堆ucHeap[256]被系統分配為:0x20000603 ~0x20000702 大小為0x100個位元組 因為記憶體管理要求位元組對齊(8),所以pucAlignedHeap 為0x20000608作為後面記憶體操作的起始地址。 configADJUSTED_HEAP_SIZE=256(0x100)-8 =248個表示可以操作的記憶體的安全範圍。 則結束地址為0x20000700 則記憶體堆實際的可活動範圍為 0x20000608~0x20000700 獲取記憶體:加入申請記憶體 30個位元組 則為其分配32個位元組,滿足其位元組對齊要求 xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); xNextFreeByte +=xWantedSize //記錄使用記憶體數量 **************************************/
//pvPortMalloc()實現起來非常簡單,需要注意的是分配記憶體之後不允許再釋放 #include <stdlib.h> #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE #include "FreeRTOS.h" #include "task.h" #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE #if( configSUPPORT_DYNAMIC_ALLOCATION == 0 ) //必須是預設支援動態分配的,否則編譯會報錯的 #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0 #endif //由於可能出現的記憶體對齊的問題,所以直接捨棄一個對齊單位. //這樣導致實際的陣列大小可能小於申請的大小 /* A few bytes might be lost to byte aligning the heap start address. */ #define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT ) /* Allocate the memory for the heap. */ #if( configAPPLICATION_ALLOCATED_HEAP == 1 ) // 1 使能自定義堆疊 0編譯器決定 /* The application writer has already defined the array used for the RTOS heap - probably so it can be placed in a special segment or address. */ extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; #else static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; #endif /* configAPPLICATION_ALLOCATED_HEAP */ /* Index into the ucHeap array. */ static size_t xNextFreeByte = ( size_t ) 0; //表示已經使用過的記憶體數量 // static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] 由系統分配陣列 // configADJUSTED_HEAP_SIZE 為可用的實際大小 xNextFreeByte記錄了使用的記憶體數量
/*---------申請記憶體實際上是從ucHeap 中獲取一塊記憶體,然後返回---------*/
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 ) );
} //如果對齊的巨集定義了,則要求申請的數量是 portBYTE_ALIGNMENT 的整數倍。
}
#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 ) ) );
//思考一下:為什麼取的 ucHeap[ portBYTE_ALIGNMENT ]的地址而不是 ucHeap[0]的地址。
//首地址需要對齊: 1-7 均要被捨棄 ,取ucHeap[ portBYTE_ALIGNMENT ]可以保證捨棄後,滿足8位對齊且不越界
}
//判斷 (已使用的 + 新申請的 < 能提供的 )且(已使用的 + 新申請的 > 已使用的)
/* 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;
}
/*-----------------------------------------------------------*/
/*
vPortFree 什麼也不做,xNextFreeByte只會增加,不會減小,因此陣列中的記憶體一旦使用,就再也不會被回收
*/
void vPortFree( void *pv )
{
/* Memory cannot be freed using this scheme. See heap_2.c, heap_3.c and
heap_4.c for alternative implementations, and the memory management pages of
http://www.FreeRTOS.org for more information. */
( void ) pv;
/* Force an assert as it is invalid to call this function. */
configASSERT( pv == NULL );
}
/*-----------------------------------------------------------*/
/* 初始化,由於所有的記憶體都是靜態的,因此只要對xNextFreeByte進行賦值即可 */
void vPortInitialiseBlocks( void )
{
/* Only required when static memory is not cleared. */
xNextFreeByte = ( size_t ) 0;
}
/*-----------------------------------------------------------*/
/*獲取當前可用記憶體 */
size_t xPortGetFreeHeapSize( void )
{
return ( configADJUSTED_HEAP_SIZE - xNextFreeByte );
}