FreeRtos内存管理-heap_1.c
FreeRTOS 支持5种动态内存管理方案,分别通过文件 heap_1.c
,heap_2.c
,heap_3.c
,heap_4.c
和heap_5.c
实现。这 5 个文件在 FreeRTOS源码包中的路径是:FreeRTOS\Source\portable\MemMang
可通过对kernel/rtos/FreeRTOS/module.mk
中的RTOS_FILES
进行设置,选择本系统选用的为哪一种内存管理方式
本文将简单介绍heap_1.c、heap_2.c、heap_3.c的代码实现以及应用场景。若用户想要自己使用内存,则可通过函数对齐进行申请调用,类似于C中的malloc()和free(),在FreeRtos中对应的函数接口为:
- void *pvPortMalloc( size_t xSize );//内存申请函数
- void vPortFree( void *pv );//内存释放函数
1.1 简介
这种内存分配方式最简单直接,速度快程序简单。适用于分配完内存后不需要回收的场合。即为在FreeRTOS系统中申请了一个很大的数组,每次pvPortMalloc()后,则从这个数组中分配对应的xWantedSize,也就是将大数组分为更小的内存块,但并不对分配的内存进行释放。
数组的总大小由FreeRTOSConfig.h
中的configTOTAL_HEAP_SIZE
定义,单位为字节。
弊端:以该种方式定义一个巨型数组会让整个应用程序耗费很多不必要的内存。
1.2 应用场景
如果应用程序不需要删除任务、队列、信号量,则可使用heap_1.c中的内存管理方法。
每个任务在创建时,需要在堆空间上分配一个TCB(任务控制块)和Stack(栈空间)。下图为heap_1.c在任务创建时的情况。
1.3 学习过程中遇到的问题
- 因为整个内存管理中,只有内存分配,没有释放,若整个栈空间满了,那这种内存管理的方式有何应对方法?
- 首先,系统分配的内存块时十分巨大的,所以可能导致整体的运行速度减慢;其次,若栈空间满了,那后续系统则将这片内存锁死,不让其他人使用。
1.4 源码解析:
1.4.1 内存申请
void *pvPortMalloc( size_t xWantedSize )
为FreeRTOS中的内存分配函数,接下来主要对整个源码进行解析。
void *pvPortMalloc( size_t xWantedSize )
{
void *pvReturn = NULL;
static uint8_t *pucAlignedHeap = NULL;//定义静态变量,用于存放对齐后的首地址
/* 确保内存块始终与所需的字节数对齐。 */
#if( portBYTE_ALIGNMENT != 1 )
{
if( xWantedSize & portBYTE_ALIGNMENT_MASK )
{
/* 字节强制对齐 */
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
}
}
#endif
vTaskSuspendAll();//任务挂起,防止重入
{
if( pucAlignedHeap == NULL )
{
/* 确保堆在正确对齐的边界上启动,即实现字节对齐 */
pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
}
/* 检查剩余空间是否足够,且没有溢出 */
if( ( ( xNextFreeByte + xWantedSize ) < configADJUSTED_HEAP_SIZE ) &&
( ( xNextFreeByte + xWantedSize ) > xNextFreeByte ) )
{
/* 返回下一个空闲字节,然后增加超过此块的索引。 */
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.4.2 内存释放
可通过void vPortFree( void *pv )
函数对申请的内存进行释放,但heap_1.c中并不做内存释放处理。
void vPortFree( void *pv )
{
/* 使用此方案无法释放内存。 */
( void ) pv;
/* 强制执行assert,因为调用此函数无效。 */
configASSERT( pv == NULL );
}
1.4.3 内存管理初始化
void vPortInitialiseBlocks( void )
{
/* 仅在静态内存未被清除时需要。 */
xNextFreeByte = ( size_t ) 0;
}
1.4.4 获取动态内存剩余空间
size_t xPortGetFreeHeapSize( void )
{
/* 唯一需要注意的就是,其大小是在对齐之后的! */
return ( configADJUSTED_HEAP_SIZE - xNextFreeByte );
}