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

目录
  • 动态内存管理
    • heap_1.c 内存堆管理
    • 实际可用数组字节数
    • 分配
    • 释放
    • 还剩空闲字节数

动态内存管理

FreeRTOS提供5种动态内存管理策略,分别为heap_1到heap_5,源码在FreeRTOS/Source/portable/MemMang下,本质是对一个或者多个大数组进行操作来对系统提供内存的申请、释放(有的策略没有)功能。下面先看看heap_1是怎么做的。

heap_1.c 内存堆管理

大数组在哪里

/* Allocate the memory for the heap. */
#if( configAPPLICATION_ALLOCATED_HEAP == 1 )
//这种情况是可以把待管理的数组分配在外部SRAM、SDRAM中
	extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
//这种情况是把待管理的数组分配在内部RAM,由编译器决定地址
	static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif /* configAPPLICATION_ALLOCATED_HEAP */

可以看到这个局部静态全局大数组名字是ucHeap,大小是configTOTAL_HEAP_SIZE,这个宏在FreeRTOSConfig.h中定义

实际可用数组字节数

//因为需要字节对齐,所以实际能使用的内存字节数要减去portBYTE_ALIGNMENT
/* A few bytes might be lost to byte aligning the heap start address. */
#define configADJUSTED_HEAP_SIZE	( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )

portBYTE_ALIGNMENT 在portmacro.h中定义

#define portBYTE_ALIGNMENT8

已分配字节数

//已经分配了的字节数,也就是下一个空闲内存相对于首址(pucAlignedHeap)的偏移量
static size_t xNextFreeByte = ( size_t ) 0;

分配

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. */
    //如果不是1字节对齐则先需要portBYTE_ALIGNMENT字节对齐
	#if( portBYTE_ALIGNMENT != 1 )
	{
		if( xWantedSize & portBYTE_ALIGNMENT_MASK )
		{			/* Byte alignment required. */
		//如果用户申请字节数不是portBYTE_ALIGNMENT_MASK字节对齐的,先要调整到portBYTE_ALIGNMENT_MASK字节对齐
		//比如申请13字节,要求portBYTE_ALIGNMENT = 8,
		//则xWantedSize = 13+(8-(13&7))=13+(8-5)=16,
		//最终申请16字节
			xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
		}
	}
	#endif
//挂起调度器,防止函数重入
	vTaskSuspendAll();
	{
		if( pucAlignedHeap == NULL )
		//说明是第一次调用此函数需要对对内存堆初始化确保内存堆首址也是8字节对齐
		{
			/* Ensure the heap starts on a correctly aligned boundary. */
		    //假设&ucHeap是0x20000C64,
		    //则&ucHeap[ portBYTE_ALIGNMENT ]是 0x20000C64+7=0x20000C6B
		    //pucAlignedHeap = 0x20000C6B & (~0x00000007) = 0x20000C68
		    //pucAlignedHeap才是实际操作的堆首址
			pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
		}
		/* Check there is enough room left for the allocation. */
		//已经分配的字节数xNextFreeByte + 将要分配的字节数xWantedSize
		//要小于总共有的字节数configADJUSTED_HEAP_SIZE
		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;
}

其中portBYTE_ALIGNMENT_MASK是根据portBYTE_ALIGNMENT定义,在portable.h中

#if portBYTE_ALIGNMENT == 8
	#define portBYTE_ALIGNMENT_MASK ( 0x0007 )
#endif

释放

可以看到heap_1是没有提供释放,是无法释放的

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 );
}

还剩空闲字节数

size_t xPortGetFreeHeapSize( void )
{
	return ( configADJUSTED_HEAP_SIZE - xNextFreeByte );
}

适用范围、特点

适用于只需分配,不需释放场合,执行时间确定,不会产生碎片,但是内存利用率不高

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

(0)

相关推荐

  • FreeRTOS编码标准及风格指南

    目录 1.编码标准 2.命名规则 1> 变量 2> 函数 1.编码标准 FreeRTOS的核心源代码遵从MISRA编码标准指南.这个标准篇幅稍长,你可以在MISRA官方网站花少量钱买到,这里不再复制任何标准. FreeRTOS源代码不符合MISRA标准的项目如下所示: 有两个API函数有多个返回点.MISRA编码标准强制规定:一个函数在其结尾应该有单一的返回点. 指针算数运算,在创建任务时,为了兼容8.16.20.24.32位总线,不可避免的使用了指针算数运算.MISRA编码标准强制规定:指针

  • FreeRTOS实时操作系统结构示例

    目录 1.查找相关文档页 2.获取RTOS源代码 3.FreeRTOS源码目录结构 移植层目录举例: 演示例程目录举例: 4.编译工程 5.运行演示例程 FreeRTOS可以被移植到很多不同架构的处理器和编译器.每一个RTOS移植都附带一个已经配置好的演示例程,可以方便快速启动开发.更好的是,每个演示例程都附带一个说明网页,提供如何定位RTOS演示工程源代码.如何编译演示例程.如何配置硬件平台的全部信息. 演示例程说明网页还提供基本的RTOS移植细节信息,包括如何编写FreeRTOS兼容的中断服

  • freertos实时操作系统临界段保护开关中断及进入退出

    目录 中断的基础知识 嵌套: 优先级: 中断的悬起与解悬: 咬尾中断Tail‐Chaining: 晚到的高优先级异常: 进入临界段和退出临界段 中断的基础知识 嵌套: 嵌套向量中断控制器 NVIC(Nested Vectored Interrupt Controller与内核是紧耦合的.提供如下的功能:可嵌套中断支持.向量中断支持.动态优先级调整支持.中断延迟大大缩短. 中断可屏蔽. 所有的外部中断和绝大多数系统异常均支持可嵌套中断.异常都可以被赋予不同的优先级,当前优先级被存储在 xPSR的专

  • FreeRTOS实时操作系统临界段保护场合示例

    目录 临界段保护场合 非中断场合 中断场合 临界段保护场合 FreeRTOS中临界段保护有2种场合,中断和非中断,通过关中断(或者关部分中断)来实现临界保护. 非中断场合 task.h 中 #define taskENTER_CRITICAL()portENTER_CRITICAL() #define taskEXIT_CRITICAL()portEXIT_CRITICAL() portmacro.h中 #define portENTER_CRITICAL()vPortEnterCritical

  • FreeRTOS操作系统的配置示例解析

    目录 1. FreeRTOSConfig.h 文件 2.  “INCLUDE_” 开始的宏 3.“config”开始的宏 FreeRTOS 的系统配置文件为 FreeRTOSConfig.h,在此配置文件中可以完成 FreeRTOS 的裁剪和配置. 1. FreeRTOSConfig.h 文件 FreeRTOS 的配置基本是通过在 FreeRTOSConfig.h 中使用“#define”这样的语句来定义宏定义实现的.在 FreeRTOS 的官方 demo 中,每个工程都有一个 FreeRTOS

  • FreeRTOS动态内存分配管理heap_1示例

    目录 动态内存管理 heap_1.c 内存堆管理 实际可用数组字节数 分配 释放 还剩空闲字节数 动态内存管理 FreeRTOS提供5种动态内存管理策略,分别为heap_1到heap_5,源码在FreeRTOS/Source/portable/MemMang下,本质是对一个或者多个大数组进行操作来对系统提供内存的申请.释放(有的策略没有)功能.下面先看看heap_1是怎么做的. heap_1.c 内存堆管理 大数组在哪里 /* Allocate the memory for the heap.

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

    目录 heap_2.c 内存堆管理 分配 初始化内存堆 把新构造的结构体插入空闲链表 释放 还剩空闲字节数 适用范围.特点 heap_2.c 内存堆管理 heap_2和heap_1一样是开辟一个大数组作为堆空间供用户使用,但是采用单项不循环链表来管理内存的分配释放,主要思想是用链表把内存块串起来,数据结构如下 /* Define the linked list structure. This is used to link free blocks in order of their size.

  • FreeRTOS动态内存分配管理heap_5示例

    目录 heap_5.c vPortDefineHeapRegions 常见问题 heap_5.c heap5与heap4分配释放算法完全相同,只是heap5支持管理多块不连续的内存,本质是将多块不连续内存用链表串成一整块内存,再用heap4算法来分配释放.若使用heap5则在涉及到分配释放的函数调用时要先调用vPortDefineHeapRegions把多块不连续内存串成一块初始化. vPortDefineHeapRegions 此函数原型 void vPortDefineHeapRegions

  • FreeRTOS动态内存分配管理heap_4示例

    目录 heap_4.c 内存堆管理 数据结构如下 分配 内存堆初始化 把新构造的结构体插入空闲链表 释放 还剩空闲字节数 历史剩余最小字节数 适用范围.特点 heap_4.c 内存堆管理 heap_4也是用链表来管理,但是链表头用的是结构体,链表尾用的是指针,链表尾占用ucHeap内存 数据结构如下 /* Define the linked list structure. This is used to link free blocks in order of their memory addr

  • C语言编程C++动态内存分配示例讲解

    目录 动态内存管理 为什么存在动态内存分配 动态内存函数的介绍 malloc申请空间和free释放空间 有借有还 free释放内存 calloc申请内存 realloc调整动态内存的大小 realloc使用的注意事项 当然realloc也可以直接开辟空间 常见的动态内存错误 1.对NULL指针的解引用操作 2.对动态开辟空间的越界访问 3.对非动态开辟内存使用free释放 4.使用free释放一块动态内存开辟的一部分 5.对同一块动态内存多次释放 6.动态开辟内存忘记释放(内存泄漏) 几个面试题

  • C语言编程动态内存分配常见错误全面分析

    目录 前言:为什么存在动态内存分配? 一.动态内存函数 1.malloc和free函数 2.calloc函数 3.realloc函数 二.常见错误 1.对NULL指针解引用 2.对动态开辟空间的越界访问 3.对非动态开辟使用free函数 4.使用free释放一块动态内存开辟内存的一部分 5.对同一块空间多次释放 6.动态开辟内存忘记释放 总结 前言:为什么存在动态内存分配? 我们已经掌握的内存开辟方式如下 int a=10;//在栈空间上开辟4字节 char arr[10]={0};//在栈空间

  • C语言动态内存分配的详解

    C语言动态内存分配的详解 1.为什么使用动态内存分配 数组在使用的时候可能造成内存浪费,使用动态内存分配可以解决这个问题. 2. malloc和free C函数库提供了两个函数,malloc和free,分别用于执行动态内存分配和释放. (1)void *malloc(size_t size); malloc的参数就是需要分配的内存字节数.malloc分配一块连续的内存.如果操作系统无法向malloc提供更多的内存,malloc就返回一个NULL指针. (2)void free(void *poi

  • 动态内存分配导致影响Javascript性能的问题

    内存分配对性能的影响是很大的,分配内存本身需要时间,垃圾回收器回收内存也需要时间,所以应该尽量避免在堆里分配内存.不过直到最近优化HoLa cantk时,我才深刻的体会到内存分配对性能的影响,其中有一个关于arguments的问题挺有意思,写在这里和大家分享一下. 我要做的事情是用webgl实现canvas的2d API(这个话题本身也是挺有意思的,有空我们再讨论),drawImage是一个重要的函数,游戏会频繁的调用它,所以它的性能至关重要.drawImage的参数个数是可变的,它有三种形式:

  • C语言动态内存分配函数的实现

    在C中我们开辟内存空间有两种方式 : 1.静态开辟内存 :例如: int a;int b[10]; 这种开辟内存空间的特点是 所开辟的内存是在栈中开辟的固定大小的 ,如a是4字节 ,数组b是40字节 ,并且数组在申明时必须指定其长度 , 如果是全局数组的话,内存是在编译时分配好的,如果是局部变量数组的话,运行时在栈上静态分配内存.不管是全局数组还是局部数组,它们都有一个特点,那就是数组大小是确定的,是代码中写死的.那如果我们想在程序运行时才确定一个数组的大小 , 前两种在栈上分配内存的方法显然是

  • Android NDK开发(C语言--动态内存分配)

    1.C 内存管理函数 C 语言为内存的分配和管理提供了几个函数.这些函数可以在 <stdlib.h> 头文件中找到. 序号 函数和描述 1 void calloc(int num, int size); 在内存中动态地分配 num 个长度为 size 的连续空间,并将每一个字节都初始化为 0.所以它的结果是分配了 numsize 个字节长度的内存空间,并且每个字节的值都是0. 2 void free(void *address); 该函数释放 address 所指向的内存块,释放的是动态分配的

随机推荐