热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

FreeRTOS的堆管理(heap_1heap_5)

FreeRTOS的堆管理上文对FreeRTOs的目录结构进行了说明,其中提到了FreeRTOS\Source\portable\MemMang目录下的五个heap_n.c文件,本文

FreeRTOS的堆管理

上文对FreeRTOs的目录结构进行了说明,其中提到了FreeRTOS\Source\portable\MemMang目录下的五个heap_n.c文件,本文将对这个五个文件的作用、差异、使用场景进行对比,以便选择出适合自己项目的堆管理模式。



  • FreeRTOS使用pvPortMalloc()来分配内存。

  • vPortFree()来释放内存。


Heap_1.c

主要用于小型专一嵌入式系统。内核在任何实时任务执行之前先分配内存,一次分配永久使用并不再改变,可靠性较高。

堆的总容量 configTOTAL_HEAP_SIZE 在 FreeRTOSConfig.h 文件中配置

每创建一个任务都会分配一个堆控制块(TCB:Task control block)和一个栈(Stack)

技术分享图片



  • A:代表整个可分配空间

  • B:当一个任务被创建出来

  • C:当三个任务被创建出来


Heap_2.c



  • Heap_2 保留的主要目的是向后兼容,不推荐在新项目中使用。可使用Heap_4作为替代。

  • Heap_2 采用最佳适配算法,适用于需要频繁创建和删除需要分配固定栈内存的任务。


Heap_3.c



  • 在heap3.c中 configTOTAL_HEAP_SIZE的配置将不再生效。

  • Heap_3通过暂时挂起FreeRTOS的调度来实现malloc()和free()的线程安全。(待补充)


Heap_4.c



  • Heap_4采用首次适应算法来分配内存。heap4将相邻未分配的内存结合成为整个大内存来减少碎片内存。


Heap5.c



  • heap_5和heap_4的使用完全一致。

  • heap_5可以对任意位置的空间进行分配,

  • heap_5在使用之前需要通过vPortDefineHeapRegions()函数进行初始化,之后才可以使用pvPortMalloc()进行内存分配。

  • PortDefineHeapRegions()的作用是明确每个分散空间的初始位置和大小。

    • 原型描述: void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions );

    • 返回值结构



typedef struct HeapRegion
{
/* 内存块的起始地址将成为堆的一部分.*/
uint8_t *pucStartAddress;
/* 堆的容量大小bytes. */
size_t xSizeInBytes;
} HeapRegion_t;

下图表示vPortDefineHeapRegions函数的具体使用场景RAM1,RAM2,RAM3分别代表三个空闲空间
技术分享图片

/* 图最左侧堆:A 定以RAM1-3的基本信息. */
#define RAM1_START_ADDRESS ( ( uint8_t * ) 0x00010000 )
#define RAM1_SIZE ( 65 * 1024 )
#define RAM2_START_ADDRESS ( ( uint8_t * ) 0x00020000 )
#define RAM2_SIZE ( 32 * 1024 )
#define RAM3_START_ADDRESS ( ( uint8_t * ) 0x00030000 )
#define RAM3_SIZE ( 32 * 1024 )
const HeapRegion_t xHeapRegions[] =
{
{ RAM1_START_ADDRESS, RAM1_SIZE },
{ RAM2_START_ADDRESS, RAM2_SIZE },
{ RAM3_START_ADDRESS, RAM3_SIZE },
{ NULL, 0 } /* 标志数组的结尾. */
};
int main( void )
{
/* 初始化heap_5 */
vPortDefineHeapRegions( xHeapRegions );

/* 编码区域。*/
}


  • A仅仅展示了RAM结构,图B 包含了堆分配的一些细节



  • 由于RAM的管理需要链接脚本,图B RAM1包含了链接脚本,RAM2,和RAM3为空。RAM1被分为两个区域,0x10000-0x01nnnn用来存放连接脚本,只有0x01nnnn-0x01FFFF可用,即heap5的可用空间为0x01nnnn-0x01FFFF,RAM2,RAM3。此时如果起始位置依然以0x010000作为起点将覆盖存放变量的内存,所以必须从0x0001nnnn作为起点,可以在HeapRegion_t结构中使用xHeapRegions[] 数组作为起始地址,但由于起始地址难判定,后续结构的必要更新,堆重叠的问题此方案并不推荐。



  • 完美推荐方案C



* 定以没有被链接器使用的两个起始地址和容量 */
#define RAM2_START_ADDRESS ( ( uint8_t * ) 0x00020000 )
#define RAM2_SIZE ( 32 * 1024 )
#define RAM3_START_ADDRESS ( ( uint8_t * ) 0x00030000 )
#define RAM3_SIZE ( 32 * 1024 )
/* 定义一个数组为heap_5使用的一部分,此数组将会被链接器放置于RAM1 */
#define RAM1_HEAP_SIZE ( 30 * 1024 )
static uint8_t ucHeap[ RAM1_HEAP_SIZE ];
/* 定义一个数组HeapRegion_t,第一个入口只定义了ucHeap数组。像之前一样HeapRegion_t结构定以仍需地址从小到大排列。*/
const HeapRegion_t xHeapRegions[] =
{
{ ucHeap, RAM1_HEAP_SIZE },
{ RAM2_START_ADDRESS, RAM2_SIZE },
{ RAM3_START_ADDRESS, RAM3_SIZE },
{ NULL, 0 } /* 标志数组的结束. */
};

优势



  • 初始地址不再是常量

  • 链接器自动设置HeapRegion_t结构

  • 内存分配给heap_5的数据不会被链接器覆盖

  • 如果ucHeap太大应用将不会链接


堆分配相关函数



  • size_t xPortGetFreeHeapSize( void ); 当被调用时返回堆中可用字节,可用于优化堆大小。当时用heap_3分配方案时此函数不生效。

  • size_t xPortGetMinimumEverFreeHeapSize( void ); 当调用时返回FreeRTOS应自开始运行从未存在于堆中的最小未分配字节。 可用于了解是否存在堆溢出情况。 **只可用于heap_4,heap_5堆分配方案中。

  • void vApplicationMallocFailedHook( void );
    内存分配的情况无处不在,可在应用中直接调用,此外在freeRTOS创建任务,队列,信号量等操作时也会调用pvPortMalloc()函数。当pvPortMalloc()未找到符合大小的RAM空间时返回NULL,此时可调用回调函数vApplicationMallocFailedHook。

    • 当在FreeRTOSConfig.h配置了configUSE_MALLOC_FAILED_HOOK为1 则表示内存分配出错时必须执行vApplicationMallocFailedHook函数。




推荐阅读
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 本文介绍了使用Python解析C语言结构体的方法,包括定义基本类型和结构体类型的字典,并提供了一个示例代码,展示了如何解析C语言结构体。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • PDF内容编辑的两种小方法,你知道怎么操作吗?
    本文介绍了两种PDF内容编辑的方法:迅捷PDF编辑器和Adobe Acrobat DC。使用迅捷PDF编辑器,用户可以通过选择需要更改的文字内容并设置字体形式、大小和颜色来编辑PDF文件。而使用Adobe Acrobat DC,则可以通过在软件中点击编辑来编辑PDF文件。PDF文件的编辑可以帮助办公人员进行文件内容的修改和定制。 ... [详细]
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
  • 本文介绍了django中视图函数的使用方法,包括如何接收Web请求并返回Web响应,以及如何处理GET请求和POST请求。同时还介绍了urls.py和views.py文件的配置方式。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
author-avatar
请让我来打酱油
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有