版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ZenNaiHeQiao/article/details/82757329
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 );
}