目录
基于freertos的嵌入式系统开发(三)FreeRTOS的内存管理方法1
简介
我们知道c语言中,内存的申请和释放对应于C的库函数malloc和free。malloc函数一个形参,通常是这么使用的:
int* p = (int*)malloc(size(int)); //申请一段为int大小的内存空间。
free函数:
free(p); //使用完之后应及时释放掉,防止内存泄漏。
在FreeRTOS中内存管理的接口函数为:pvPortMalloc、vPortFree,对应malloc和free,在源码中默认提供了5个文件,以最新版本\FreeRTOSv202112.00为例,该文件位于:
\FreeRTOSv202112.00\FreeRTOSv202112.00\FreeRTOS\Source\portable\MemMang
目录下,见下图:
5个文件对应内存管理的5种方法,主要特征见下表:
下面结合源码分析,对这5钟方式逐一进行分析
方式1:Heap_1.c
方式1实现了非常基础的 pvPortMalloc,没有实现 vPortFree,从来不销毁任务、或者其他内核对象,适用于资源有限、需求明确的小型专用嵌入式系统,在调度器运行之前,系统需要的 tasks 和其他内核对象已经确定并创建完毕,并且已分配的内存会保持分配状态,直到程序结束。这样就不需要考虑复杂的内存动态分配、内存泄露和碎片化问题,重点关注代码简洁、可靠等。
内存分配函数 void * pvPortMalloc( size_t xWantedSize )
最新版本\FreeRTOSv202112.00的内核版本为FreeRTOS Kernel V10.4.6,内存分配函数的的工作流程如下图:
下面看Heap_1.c的代码:
void * pvPortMalloc( size_t xWantedSize )
{
void * pvReturn = NULL;
static uint8_t * pucAlignedHeap = NULL;
/* Ensure that blocks are always aligned. 字节对齐处理 */
#if ( portBYTE_ALIGNMENT != 1 )
{
if( xWantedSize & portBYTE_ALIGNMENT_MASK )
{
/* Byte alignment required. Check for overflow. */
if ( (xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) )) > xWantedSize )
{
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
}
else
{
xWantedSize = 0;
}
}
}
#endif
vTaskSuspendAll(); //挂起所以任务
{
if( pucAlignedHeap == NULL ) /* 释放字节对齐? */
{
/* Ensure the heap starts on a correctly aligned boundary 确保内存堆的开始地址是字节对齐的 */.
pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) & ucHeap[ portBYTE_ALIGNMENT - 1 ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
}
/* Check there is enough room left for the allocation and.
检查是否有足够的内存供分配,以及是否越界 */
if( ( xWantedSize > 0 ) && /* valid size */
( ( 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();/* 分配后,恢复所有任务 */
/* 如果分配失败且定义了hook函数,则调用hook函数 */
#if ( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
extern void vApplicationMallocFailedHook( void );
vApplicationMallocFailedHook();
}
}
#endif
return pvReturn;
}
内存释放函数 void vPortFree( void * pv )
前面讲过,方式1的内存分配方式并不会释放内存,所以,该函数只是做一个invalid的assert,并没有任务释放内存操作,代码如下:
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
* https://www.FreeRTOS.org for more information. */
( void ) pv;
/* Force an assert as it is invalid to call this function. */
configASSERT( pv == NULL );
}
FreeRTOS中的断言函数configASSERT()和标准C中的断言函数assert()是一样的。
初始化 void vPortInitialiseBlocks( void )
只有在清除静态内存时需要调用,基本用不着,代码如下:
void vPortInitialiseBlocks( void )
{
/* Only required when static memory is not cleared. */
xNextFreeByte = ( size_t ) 0;
}
获取自由Heap大小 size_t xPortGetFreeHeapSize( void )
该函数可以获取可供分配的自由heap大小,可以作为下一次分配前的参考,防止出现内存申请失败的情况,当然,申请失败处理也可以在钩子函数vApplicationMallocFailedHook来处理。
代码如下:
size_t xPortGetFreeHeapSize( void )
{
return( configADJUSTED_HEAP_SIZE - xNextFreeByte );
}