堆内存管理

因为品种要求,这两天上马学习FreeRTOS,一开头有一些忐忑,因为多个礼拜在此之前对于FreeRTOS的纯熟度差不离为零,经过对FreeRTOS官方网站的例子程序的寻找,和项目中难题的缓慢解决,遭逢了许多纯熟的身影,以前在Linux平台编制程序的经验给了自家有的极度灵光的阅历,后悔当初未能在首家商城待下去,浪费了大好时光。好啊,今后依然潜下心来搞搞FreeRTOS吧。

持续都是一三种FreeRTOS相关的随笔,先把FreeRTOS“圣经”--Mastering the FreeRTOS Real Time kernel -- A Hands On Tutorial Guide 20161204巧妙研读,接连的多少个小说都是自己从那本“圣经”中翻译出来的。翻译难免有着疏漏、词不达意,我们凑合着看吗。

从FreeRTOS V9.0.0开始FreeRTOS应用程序能够完全用静态分配内存,而不须要引进堆内部存款和储蓄器管理。

章节引言和限量

前提

FreeRTOS是以C源文件的情势提供的,因而造成一名合格的C语言编制程序人士是采用FreeRTOS的要求条件,由此那些章节日假期定读者熟识以下概念:

  • C语言项目是怎么创设的,包蕴区别的编写翻译和链接进度
  • 堆和栈分别是何许
  • 标准C库的malloc()free()函数

动态内部存款和储蓄器分配以至它和FreeRTOS的涉嫌

从FreeRTOS V9.0.0发端根本对象不仅能够在编写翻译的时候静态分配,也得以在运维时动态分配。本书随后的章节将会介绍以下基本对象:tasks, queues, semaphoresevent groups。为了尽也许让FreeRTOS易于使用,那么些基本对象并非在编写翻译时静态分配的,而是在运作时动态分配的。内核查象创立时FreeRTOS分配RAM而在根本对象删除时释放内部存款和储蓄器。那样的陈设裁减了设计和安插上的卖力,简化了API,何况收缩了RAM的攻下。

动态内部存款和储蓄器分配是C语言编制程序的定义,并非针对FreeRTOS可能多职主要编辑制程序的概念。它和FreeRTOS是有关的,因为基本对象是动态分配的,何况通用编写翻译器提供的动态内部存款和储蓄器分配方案对于实时应用程序并不总是切合的。

内存能够应用标准C库的malloc()free()函数来分配,但有非常大也许不符合,或许适当,因为下几点原因:

  • 在Mini嵌入式系统中并不总是可用的
  • 它们的贯彻大概相当大,占有了一定大的一块代码空间
  • 她们差相当的少都不是线程安全的
  • 它们并非规定的,每一次调用这个函数实行的时刻只怕都不一致样
  • 它们有希望发生碎片
  • 它们有不小恐怕打乱链接器的布局
  • 假使同意堆空间的生长方向覆盖任何变量占领的内部存款和储蓄器,它们会化为debug的灾难

动态内存分配的可选项

从FreeRTOS V9.0.0起来根本对象不仅能够在编写翻译时静态分配也得以在运作时动态分配。近期FreeRTOS把内存分配放在可移植层。这是认知到差别的嵌入式操作有例外的动态内部存款和储蓄器管理方法和时间要求,因而单个的动态内部存款和储蓄器分配算法将只相符于应用程序的三个子集。同样,从着力代码库中移除动态内部存款和储蓄器分配使得应用程序编写者提供温馨的一定的落到实处,如若相符的话。

当FreeRTOS须要RAM的时候,并非调用malloc(),而是调用pvPortMalloc()。当要求释放RAM的时候,并不是调用free(),而是调用vPortFree()pvPortMalloc()和标准C库的malloc()有一样的函数原型,vPortFree()和标准C库的free()有一样的函数原型。

pvPortMalloc()vPortFree()都以公家函数,因而能够被选用代码调用。

FreeRTOS对于pvPortMalloc()vPortFree()提供了5种完毕,后续章节会讲到。FreeRTOS应用程序能够应用个中的一种,可能利用自个儿的贯彻。5种达成各自在heap_1.c, heap_2.c, heap_3.c, heap_4.cheap_5.c文本中,都设有于文件夹 FreeRTOS/Source/portable/MemMang 下。

范围

本章节从事于让读者深切理解:

  • FreeRTOS几时分配RAM
  • FreeRTOS 提供的5种内部存款和储蓄器分配方案
  • 接纳哪类内部存款和储蓄器分配方案

内部存款和储蓄器分配方案示例

Heap_4 (别的三种暂不去了然)

heap_1, heap_2 一样,heap_4也是把数组切割成越来越小的块。和后面同样,数组是静态注明的,由宏configTOTAL_HEAP_SIZE点名大小,所以这就使得纵然数组中的内部存款和储蓄器还从未被分配出去就让应用程序显得消耗了大气的RAM。

Heap_4动用了最初适应算法来分配内部存储器。和heap_2不同,heap_4把贴近的闲暇的累积空间拼凑成八个更加大的内部存款和储蓄器块,那就裁减了内部存款和储蓄器碎片化的风险。

最先适应算法确认保障了pvPortMalloc()应用第一块空闲的十足大的内部存款和储蓄器来满意要申请的字节数。缅怀上面包车型客车风貌:

  • 堆里有3块空闲内部存储器块,它们的轻重缓急分别是5个字节,200个字节,一百个字节
  • 调用pvPortMalloc()来报名19个字节的RAM
    满意字节数要求的率先块空闲RAM块是200个字节的RAM块,因而pvPortMalloc()把大小为200个字节的RAM块分割成两块,一块是二十个字节,一块是1捌13个字节,然会再次来到一个对准十捌个字节的指针。新的1八十多个字节大小的RAM块就要后续的pvPortMalloc()调用中可用。

Figure 7 演示了 heap_4 最初适应算法怎么样拼接内部存储器,一样也演示了内部存款和储蓄器的分红和假释:

银河网址 1

  1. A示范了创立3个义务之后的数组的表率,一大块空的块存在于数组的上方。
  2. B示范了删除1个职责之后的数组,一大块空的块存在于数组的上方。被剔除的十二分职务占有的TCB和栈存款和储蓄空间以往是空的,而且它们拼接成二个大的空的块。
  3. C亲自过问了FreeRTOS成立了一个Queue。队列是透过xQueueCreate() API 创立的,它是调用pvPortMalloc() 来分配存款和储蓄空间的。由于heap_4应用最初适应算法,pvportMalloc()将会动用第一块大的十足容纳队列的RAM块来分配,在Figure 7中就动用在此以前剔除职责的那一块。然则队列并不完全消耗这么些空闲的区块,所以极度RAM块会分成四个部分,未利用的有个别将会由三番五次的pvPortMalloc()占用。
  4. D身体力行了应用程序直接调用pvPortMalloc()实际不是直接地由FreeRTOS API调用之后的情事。顾客分配的区块丰盛小,可以放在第一个空闲的区块中,这么些区块正是队列占用的区块和前边的TCB占用的区块之间的那一块。
    剔除职分释放的内部存款和储蓄器,未来被分割成3个区块,第四个区块是队列,第3个区块是客户分配的,第八个区块如故空的。
  5. E 演示了队列删除之后,存款和储蓄空间也自动释放了。现在客户分配的区块两侧都以空闲区块。
  6. F 演示了客商分配的储存空间释放的意况。这些区块未来和两侧的空闲区块拼接成了三个更大的空闲区块。

Heap_4并非扎眼的,可是要比正规库函数达成的malloc()free()运转的越来越快。

设定Heap_4数组的胚胎地址

此章节满含更加高阶的音讯,仅仅为了选拔Heap_4是未曾要求阅读和清楚此章节的。

一点时候应用程序开垦者必要钦赐heap_4数组的开场馆址位于有个别特定的内部存款和储蓄器。举个例子,FreeRTOS 职务的栈是从堆中分配的,就有十分的大只怕有供给保险堆是分配在赶快的内部存储器中,实际不是慢速的外部存款和储蓄器。

暗中认可情形下,heap_4数组是在heap_4.c源文件中表明的,它的开头地址是由链接器自动明确的。但是,假使在文书FreeRTOSConfig.h中把编写翻译时安排选项configAPPLICATION_ALLOCATED_HEAP设为常量1,那么数组必需由使用FreeRTOS的利用注脚。假诺把数组注明为利用的一片段,那么应用编写者能够内定数组的开局部址。

倘若把公文FreeRTOSConfig.h中的configAPPLICATION_ALLOCATED_HEAP设定为1,那么应用程序源文件中必需声可瑞康个名叫ucHeapuint8_t品种的数组,它的高低有configTOTAL_HEAP_SIZE设定。

把变量放在有些内部存储器地址的语法决计于使用了哪一种编写翻译器,上面演示了二种编写翻译器的用法:

  1. Listing 2演示的是GCC编写翻译器注脚数组并把数组放在名为.my_heap的段中。
  2. Listing 3演示的是IA帕杰罗编写翻译器把数组放在内部存款和储蓄器相对地址0x20000000上。

uint8_t ucHeap [configTOTAL_HEAP_SIZE] attribute (( section(".my_heap") ));

Listing 2

uint8_t ucHeap [configTOTAL_HEAP_SIZE] @ 0x20000000;

Listing 3

和堆相关的实用函数

xPortGetFreeHeapSize() API

这一个函数可以赢得调用时堆中空闲内部存款和储蓄器的大小,以字节为单位。使用它可以优化堆的轻重缓急。举个例子,当内核对象都创设完结后调用xPortGetFreeHeapSize()回去两千,那么能够把configTOTAL_HEAP_SIZE减小2000.

亟需注意,当使用heap_3时是不可能调用这些函数的。

xPortGetMinimumEverFreeHeapSize() API

此函数重临FreeRTOS应用程序初叶运维之后已经存在的细微的未被分配的囤积空间的字节数。它的再次来到值提醒了应用程序离就要耗尽堆空间的好像程度。比方xPortGetMinimunEverFreeHeapSize()回来200个字节,那么从应用程序开始运转之后的有个别时刻,在应用200个字节就能够把堆空间用完。

亟需注意,xPortGetMinimumEverFreeHeapSize()只在行使heap_4或者heap_5时生效。

Malloc 失败钩子函数

应用程序能够平素调用pvPortMalloc()。当然在FreeRTOS源文件中每当内核查象创制时也会调用这么些函数。此类的木本对象包涵职责,队列,数字信号量和事件组。

和规范库函数malloc()银河网址,一样,如果pvPortMalloc()因为申请RAM的轻重不可能知足未能再次来到一块RAM上空就能够重临NULL。要是编制程序职员调用pvPortMalloc()来成立基础对象,但是回去NULL就认证内核对象未有创建形成功。

事例中的全数堆分配方案都可以给pvPortMalloc()布署多个钩子函数(也称作回调函数),当pvPortMalloc()返回NULL时调用这几个钩子函数。

即便文件FreeRTOSConfig.h中的configUSE_MALLOC_FAILED_HOOK设置为1,那么应用程序必得提供三个内部存款和储蓄器分配退步时的钩函数,它的名字和原型参见如下。只要对这些利用来讲是适当的,那个钩子函数能够用任何格局来兑现。

void vApplicationMallocFailedHook( void );

声明

招待转发,请表明出处和小编,相同的时候保留证明。
作者:LinTeX9527
出处:
本博客的篇章如无特殊表明,均为原创,转载请评释出处。如未经笔者同意必得保留此段注解,且在篇章页面显然地方给出原著连接,不然保留追究法律义务的义务。

本文由银河网址发布于银河网址,转载请注明出处:堆内存管理

您可能还会对下面的文章感兴趣: