我的编程空间,编程开发者的网络收藏夹
学习永远不晚

FreeRTOS动态内存分配管理heap_2示例

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

FreeRTOS动态内存分配管理heap_2示例

heap_2.c

内存堆管理

heap_2和heap_1一样是开辟一个大数组作为堆空间供用户使用,但是采用单项不循环链表来管理内存的分配释放,主要思想是用链表把内存块串起来,数据结构如下


typedef struct A_BLOCK_LINK
{
   //指向下一个空闲内存块管理结构体
	struct A_BLOCK_LINK *pxNextFreeBlock;	
	//记录申请的字节数,包括链表占用所占字节数
	size_t xBlockSize;						
} BlockLink_t;

与引入链表管理而带来的相关变量如下

//链表结构体对齐后所占字节数
static const uint16_t heapSTRUCT_SIZE	= ( ( sizeof ( BlockLink_t ) + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK );
//2倍链表结构体对齐后所占字节数,这作为一个阈值,在分配时起作用
#define heapMINIMUM_BLOCK_SIZE	( ( size_t ) ( heapSTRUCT_SIZE * 2 ) )

//定义2个局部静态全局结构体变量用于管理
static BlockLink_t xStart, xEnd;

还剩空闲字节数


static size_t xFreeBytesRemaining = configADJUSTED_HEAP_SIZE;

分配

void *pvPortMalloc( size_t xWantedSize )
{
BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
static BaseType_t xHeapHasBeenInitialised = pdFALSE;
void *pvReturn = NULL;
//挂起调度器,防止函数重入
	vTaskSuspendAll();
	{
		
		//第一次调用会初始化内存堆
		if( xHeapHasBeenInitialised == pdFALSE )
		{
			prvHeapInit();
			xHeapHasBeenInitialised = pdTRUE;
		}

		
		if( xWantedSize > 0 )
		{
		    //用户分配字节数+管理结构体占用字节数
			xWantedSize += heapSTRUCT_SIZE;

			
			//总的字节数再做此字节对齐
			if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0 )
			{
				
				xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
			}
		}
        //待分配字节数大于0且小于总共堆字节数
		if( ( xWantedSize > 0 ) && ( xWantedSize < configADJUSTED_HEAP_SIZE ) )
		{
			
			//pxPreviousBlock指向头链表
			pxPreviousBlock = &xStart;
			//pxBlock指向第一个开始空闲块
			pxBlock = xStart.pxNextFreeBlock;
			//当pxBlock所管理的空闲块字节数小于待分配的
			//且没有遍历到空闲块管理链表尾部则一直遍历
			while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
			{
				//pxPreviousBlock这里是保存当前空闲块管理结构体,为了后面找到返回的内存地址
				pxPreviousBlock = pxBlock;
				//指向下一个空闲块管理结构体
				pxBlock = pxBlock->pxNextFreeBlock;
			}
			
			//pxBlock不等于结尾说明找到符合大小的空闲块
			if( pxBlock != &xEnd )
			{
				
				//pvReturn用作返回给用户,这里要偏移一个空闲块管理结构体占用内存大小
				pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );

				
				//因为pxPreviousBlock->pxNextFreeBlock指向的空闲块被分配了,
				//所以要把pxPreviousBlock->pxNextFreeBlock指向的空闲块移除出去,
				//也就是pxPreviousBlock->pxNextFreeBlock指向pxBlock->pxNextFreeBlock
				//也就是跳过分配出去的那个块
				pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;

				
				//这里判断,
				//如果将要分配出去的内存块大小xBlockSize比分配出去的还要大heapMINIMUM_BLOCK_SIZE(2倍管理结构体)
				//为了节约就把再分成2块,一块返回给用户,
				//一块构造一个新的空闲管理结构体后插入空闲链表
				if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
				{
					
					//注意这里xWantedSize是管理结构体和和真正需要字节数之和
					//所以是在pxBlock基础上偏移xWantedSize作为新的管理结构体
					pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );

					
					//pxNewBlockLink新的管理结构体大小
					//是待分配pxBlock->xBlockSize-xWantedSize
					pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
					//更新pxBlock->xBlockSize大小为xWantedSize
					pxBlock->xBlockSize = xWantedSize;

					
					//把新构造的空闲管理结构体按xBlockSize大小升序插入到空闲链表
					prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
				}
                //还剩空闲字节数要减去分配出去的
				xFreeBytesRemaining -= pxBlock->xBlockSize;
			}
		}

		traceMALLOC( pvReturn, xWantedSize );
	}//解挂调度器
	( void ) xTaskResumeAll();
//如果定义了申请失败钩子函数,这里将执行
	#if( configUSE_MALLOC_FAILED_HOOK == 1 )
	{
		if( pvReturn == NULL )
		{
			extern void vApplicationMallocFailedHook( void );
			vApplicationMallocFailedHook();
		}
	}
	#endif
//返回给用户
	return pvReturn;
}

其中xFreeBytesRemaining初始化如下


static size_t xFreeBytesRemaining = configADJUSTED_HEAP_SIZE;

初始化内存堆

static void prvHeapInit( void )
{
BlockLink_t *pxFirstFreeBlock;
uint8_t *pucAlignedHeap;
	
    //与heap1操作相同,确保portBYTE_ALIGNMENT字节对齐,实际使用的首址是pucAlignedHeap
	pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
	
	//空闲链表结构体头部初始化,pxNextFreeBlock指向实际使用的首址pucAlignedHeap
	xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
	//空闲链表结构体头部没有可用内存,所以xBlockSize是0
	xStart.xBlockSize = ( size_t ) 0;
	
	//空闲链表结构体尾部初始化,xBlockSize=configADJUSTED_HEAP_SIZE仅仅是为了后面的升序排列,不代表可以空闲字节数
	xEnd.xBlockSize = configADJUSTED_HEAP_SIZE;
	//空闲链表结构体尾部初始化,pxNextFreeBlock指向NULL表示结尾
	xEnd.pxNextFreeBlock = NULL;
	
	//第一个空闲块,pxFirstFreeBlock,即上面xStart指向的pucAlignedHeap
	pxFirstFreeBlock = ( void * ) pucAlignedHeap;
	//可以空闲内存为configADJUSTED_HEAP_SIZE
	pxFirstFreeBlock->xBlockSize = configADJUSTED_HEAP_SIZE;
	//指向空闲链表结构体尾部
	pxFirstFreeBlock->pxNextFreeBlock = &xEnd;
}

初始化后的示意图如下
这里注意xBlockSize是包括管理结构体占用内存大小的(出来xStart和xEnd之外,这2个做排序用)

在这里插入图片描述

把新构造的结构体插入空闲链表



#define prvInsertBlockIntoFreeList( pxBlockToInsert )								\
{																					\
BlockLink_t *pxIterator;															\
size_t xBlockSize;																	\																					\
    //这里获得新构造的空闲结构体成员xBlockSize大小等下用于升序插入
	xBlockSize = pxBlockToInsert->xBlockSize;										\																					\
		\
												\
	//从头开始找到要插入的位置
	for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock )	\
	{																				\
			\
	}																				\																					\
			\
																		\
	//插入
	pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;					\
	pxIterator->pxNextFreeBlock = pxBlockToInsert;									\
}

释放

释放就很简单了,就是偏移下地址后直接插入空闲链表

void vPortFree( void *pv )
{
uint8_t *puc = ( uint8_t * ) pv;
BlockLink_t *pxLink;

	if( pv != NULL )
	{
		
		//偏移回地址
		puc -= heapSTRUCT_SIZE;
		
		pxLink = ( void * ) puc;
       //挂起调度器
		vTaskSuspendAll();
		{
			
		    //插入空闲链表
			prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
			//剩余空闲内存增加
			xFreeBytesRemaining += pxLink->xBlockSize;
			traceFREE( pv, pxLink->xBlockSize );
		}//解挂调度器
		( void ) xTaskResumeAll();
	}
}

还剩空闲字节数

size_t xPortGetFreeHeapSize( void )
{
	return xFreeBytesRemaining;
}

适用范围、特点

适用于需要释放的场合,且每次申请释放的内存都是固定大小的,因为释放时不会合并相邻空闲内存块,所以如果每次申请释放都是随机的,到最后即使剩余内存大于要想要分配,由于有很多小的内存碎片导致最终分配失败。

以上就是FreeRTOS动态内存分配管理heap_2示例的详细内容,更多关于FreeRTOS动态内存管理heap_2的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

FreeRTOS动态内存分配管理heap_2示例

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

FreeRTOS动态内存分配管理示例分析

本篇内容主要讲解“FreeRTOS动态内存分配管理示例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“FreeRTOS动态内存分配管理示例分析”吧!动态内存管理FreeRTOS提供5种动态内存
2023-06-29

FreeRTOS动态内存分配怎么管理heap5

今天小编给大家分享一下FreeRTOS动态内存分配怎么管理heap5的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。heap_
2023-06-29

C语言中动态内存管理的示例分析

这篇文章主要介绍了C语言中动态内存管理的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。什么是动态内存分配我们都知道在C语言中,定义变量的时候,系统就会为这个变量分配内
2023-06-25

C语言中动态内存管理实例分析

今天小编给大家分享一下C语言中动态内存管理实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1.动态内存开辟的原因常见的
2023-07-02

C语言动态内存管理实例代码分析

这篇文章主要介绍了C语言动态内存管理实例代码分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C语言动态内存管理实例代码分析文章都会有所收获,下面我们一起来看看吧。1.动态内存开辟的原因常见的内存开辟方式int
2023-07-02

C/C++内存管理的示例分析

这篇文章主要介绍了C/C++内存管理的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。C/C++赋予程序员管理内存的自由,是C/C++语言特色,虽然这引入了复杂度和危险
2023-06-15

C++中内存管理的示例分析

这篇文章将为大家详细讲解有关C++中内存管理的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。概述内存管理的原理庞大而复杂,然而这些都被操作系统进行了封装,并对外预留了API,这些api被c++调用
2023-06-25

Linux内存管理之内存回收的示例分析

这篇文章主要介绍了Linux内存管理之内存回收的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1.1 内存回收的目标不是所有的物理内存都可以参与回收的,比如要是把内核
2023-06-16

C语言中动态内存的示例分析

这篇文章主要为大家展示了“C语言中动态内存的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C语言中动态内存的示例分析”这篇文章吧。1.关于动态内存的函数1.1 malloc和free函数
2023-06-29

C语言中的动态内存分配实例分析

本篇内容主要讲解“C语言中的动态内存分配实例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C语言中的动态内存分配实例分析”吧!什么是动态内存分配我们目前已经知道的内存开辟的方式有:int v
2023-07-02

C语言动态内存管理malloc柔性数组示例详解

这篇文章主要为大家介绍了C语言动态内存管理malloc柔性数组示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

JVM内存管理深入垃圾收集器与内存分配策略的示例分析

这篇文章给大家介绍JVM内存管理深入垃圾收集器与内存分配策略的示例分析,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出
2023-06-17

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录