FreeRTOS中对于内存的管理当前一共有5种实现方式(作者当前的版本是10.1.1),均在【 \Source\portable\MemMang 】下面,这里笔记下。
heap_4.c和第二种方式比较相似,只不过增加了一个和并算法,将相邻空闲内存合并为一个大内存,和方法一、二管理策略一样,内存堆仍为一个大数组。
区别在于第四种内存管理策略的空闲块链表不是以内存块大小为存储顺序,而是以内存块起始地址大小为存储顺序,地址小的在前,地址大的在后。这也是为了适应合并算法而作的改变。
使用方法:
头文件: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;
重要参数:
重要的参数备注:
(1)FreeRTOS 内存堆为:ucHeap[] 大小为 configTOTAL_HEAP_SIZE
(2)pucAlignedHeap 作为堆栈字节对齐后的起始地址(怎么实现的思考一下)
(3)xTotalHeapSize 表示堆栈进行内存大小减去被舍弃字节后的总内存大小
(4)xStart, xEnd; 记录空闲链表的首尾。
(5)pxFirstFreeBlock 空闲链表
(6)xMinimumEverFreeBytesRemaining 是一个统计值,存储了当前模拟堆运行时的最小剩余内存容量
(7)xFreeBytesRemaining:当前模拟堆的剩余内存容量
举个例子:
内存申请:
空闲链是按照地址排序的,从链表中找出内存大小满足的内存块。相对于方式二其查询时间可能变长了。
内存释放:
释放内存后会比较前后的空闲块是否地址连接,是则内存合并。
heap_2.c分析:
将源码解析调整一下顺序:
下面是链表的初始化,heap_2.c中链表的尾部数据并未保存在链表内,是以变量的形式存在的。heap_4.c中的链表尾部数据结构保存在链表空间尾部。
下面是链表初始化代码:
//关于堆栈的初始化
//第一步:起始地址做字节对齐 保存pucAlignedHeap 可用空间大小为xTotalHeapSize
//第二步:计算首尾 ,这里需要注意的是链表的尾部指针是保存到该地址尾部的
//第三部:完成链表的初始化,记录内存块信息
static void prvHeapInit( void )
{
BlockLink_t *pxFirstFreeBlock;
uint8_t *pucAlignedHeap;
size_t uxAddress;
size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;
/* Ensure the heap starts on a correctly aligned boundary. */
//起始地址做字节对齐处理
uxAddress = ( size_t ) ucHeap;
if( ( uxAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
{
uxAddress += ( portBYTE_ALIGNMENT - 1 );
uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
xTotalHeapSize -= uxAddress - ( size_t ) ucHeap; //减去对齐舍弃的字节
}
pucAlignedHeap = ( uint8_t * ) uxAddress; //对齐后可以用的起始地址
/* xStart is used to hold a pointer to the first item in the list of free
blocks. The void cast is used to prevent compiler warnings. */
//xStart链表的头
xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
xStart.xBlockSize = ( size_t ) 0;
/* pxEnd is used to mark the end of the list of free blocks and is inserted
at the end of the heap space. */
//pxEnd链表的尾
uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;
uxAddress -= xHeapStructSize;
uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
pxEnd = ( void * ) uxAddress;
pxEnd->xBlockSize = 0;
pxEnd->pxNextFreeBlock = NULL;
/* To start with there is a single free block that is sized to take up the
entire heap space, minus the space taken by pxEnd. */
//开始时候将内存堆整个看作为一个空闲内存块
pxFirstFreeBlock = ( void * ) pucAlignedHeap;
pxFirstFreeBlock->xBlockSize = uxAddress - ( size_t ) pxFirstFreeBlock;
pxFirstFreeBlock->pxNextFreeBlock = pxEnd;
/* Only one block exists - and it covers the entire usable heap space. */
xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize; //记录最小的空闲内存块大小
xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize; //剩余内存堆大小
/* Work out the position of the top bit in a size_t variable. */
xBlockAllocatedBit = (