FREERTOS源码解析——heap4.c

本文深入解析FreeRTOS中的Heap4内存管理机制,包括其分配、释放算法,以及内存碎片处理策略。Heap4采用首次适配算法,支持内存块的拆分与合并,有效减少内存碎片,适用于随机大小的内存分配与释放场景。

内存管理

freertos目前提供了以下5种内存管理,特点如下

  1. heap1:最简单的内存管理,管理的其实是一个静态全局变量,只允许分配,不允许释放,设计之初就是用于创建信号量、任务、队列一般不需要释放的数据,不过在FreeRTOS V9.0.0及其以后版本添加 support for static allocation基本就被替代了。
  2. heap2.:比1多了内存释放,分配也因为有内存释放原因多了一个最佳适配算法,不过在内存释放后没有空闲块合并的功能,只适合信号量队列任务等大小固定的内存分配,随机大小的内存分配释放会因为内存碎片问题而无法进行。后面heap4是heap2的优化版。
  3. heap3:简单封装标准C库mallco和free,提供线程安全。
  4. heap4:一般来说FREERTOS五种堆管理里这个是最常见使用的了,首次适配算法,heap2的优化版,多了相邻内存碎片合并功能,内存碎片的风险少很多,不过没有MMU的芯片没有逻辑地址和物理地址的映射概念,内存分配就是一个萝卜一个坑,想做内存紧凑比较费劲。
  5. heap5:比heap4多了不连续地址多段内存管理,分配释放代码完全一样。

heap4无法解决的内存碎片:

在这里插入图片描述

本文主要解析heap4。

HEAP4简析

heap4的使用只需要两个接口pvPortMalloc()和vPortFree()。简要的说下重点

分配内存在哪,大小多少

静态全局变量,位于静态区

static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];

大小由FreeRTOSConfig.h 文件里的宏定义控制

#define configTOTAL_HEAP_SIZE					((size_t)(40*1024))    

如何管理

freertos基本只对空闲块做管理,heap4也一样,空闲块做链表管理,并且链表排序内存地址从小到大管理,上文也说到,是首次适应算法,这么做主要便于内存空闲块合并。
分配:从空闲块找第一个大小合适的空闲块,空闲块大小减去需要的内存扔满足最小空闲块要求,该空闲块把剩余内存拆分出来做新的一个空闲块插入继续按地址排列继续插入内存空闲链表中
释放:根据释放首地址,释放对应内存块,将内存块按地址插入到空闲块链表里,如果空闲块与相邻内存块地址连续,则合并为一个大空闲内存块

图网上找的的,作者未知
在这里插入图片描述

在这里插入图片描述

  • xStart:静态场两,空闲块链表首节点,指向第一个空闲块节点
  • pxEnd:结构体指针,地址是ucHeap末尾,空闲链表尾节点,nextpoint指向null,标志链表结束。

heap4 分配模型图,A->F
在这里插入图片描述
结合图文,算是比较大概的介绍了heap4的管理模型,其中还有些字节对齐及一些细节内容由结合源码分析

重要源码解析

typedef struct A_BLOCK_LINK   //空闲块节点,具体的分配内存返回的的指针实际上是该块的下一个地址,
							//也就是说此结构体只是一个节点信息
{
   
   
	struct A_BLOCK_LINK *pxNextFreeBlock;	/*<< 下一个空闲块. */
	size_t xBlockSize;						/*<< 该块的大小. 最高位代表该块是否被分配*/
} BlockLink_t;

static void prvHeapInit( void )  //堆初始化,不需要用户调用,第一次pvPortMalloc()会执行该函数
{
   
   
BlockLink_t *pxFirstFreeBlock;
uint8_t *pucAlignedHeap;
size_t uxAddress;
size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;

/* 8字节对齐,因为AAPCS规则要求堆栈8字节对齐 */
	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 存储空闲节点连表首节点*/
	xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
	xStart.xBlockSize = ( size_t ) 0;

	/* pxEnd 和xStart不同,pxEND是一个指针指向堆空闲末尾,标记空闲块链表的结束*/
	uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;
	uxAddress -= xHeapStructSize;
	uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
	pxEnd = ( void * ) uxAddress;
	pxEnd->xBlockSize 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值