FreeRTOS–堆内存管理

前提

FreeRTOS是以C源文件的情势提供的,由此成为一名合格的C语言编程人士是利用FreeRTOS的必要条件,由此那个章节假定读者熟识以下概念:

  • C语言项目是怎么样构建的,包含不同的编译和链接过程
  • 堆和栈分别是什么样
  • 标准C库的malloc()free()函数

xPortGetMinimumEverFreeHeapSize() API

此函数重临FreeRTOS应用程序开首运行之后一度存在的细微的未被分配的仓储空间的字节数。它的再次来到值提示了应用程序离将要耗尽堆空间的好像程度。例如xPortGetMinimunEverFreeHeapSize()回去200个字节,那么从应用程序先河运行之后的某部时刻,在拔取200个字节就会把堆空间用完。

亟需小心,xPortGetMinimumEverFreeHeapSize()只在采用heap_4或者heap_5时生效。

xPortGetFreeHeapSize() API

其一函数可以得到调用时堆中空闲内存的深浅,以字节为单位。使用它可以优化堆的轻重。例如,当内核对象都创设完毕后调用xPortGetFreeHeapSize()再次回到2000,那么可以把configTOTAL_HEAP_SIZE减小2000.

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

声明

迎接转载,请阐明出处和作者,同时保留表明。
作者:LinTeX9527
出处:http://www.cnblogs.com/LinTeX9527/p/8007541.html
本博客的稿子如无特殊表明,均为原创,转载请声明出处。如未经作者同意必须保留此段注脚,且在篇章页面分明位置给出原文连接,否则保留追究法律责任的权利。

章节引言和限制

Heap_4 (其他两种暂不去询问)

heap_1, heap_2
一样,heap_4也是把数组切割成更小的块。和前边一样,数组是静态注解的,由宏configTOTAL_HEAP_SIZE指定大小,所以这就使得即使数组中的内存还尚未被分配出去就让应用程序显得消耗了汪洋的RAM。

Heap_4采用了起先适应算法来分配内存。和heap_2不同,heap_4把贴近的悠闲的贮存空间拼凑成一个更大的内存块,这就缩小了内存碎片化的高风险。

第一适应算法确保了pvPortMalloc()动用第一块空闲的足足大的内存来满意要提请的字节数。考虑下边的现象:

  • 堆里有3块空闲内存块,它们的轻重分别是5个字节,200个字节,100个字节
  • 调用pvPortMalloc()来报名20个字节的RAM
    知足字节数要求的第一块空闲RAM块是200个字节的RAM块,因而pvPortMalloc()把大小为200个字节的RAM块分割成两块,一块是20个字节,一块是180个字节,然会重返一个对准20个字节的指针。新的180个字节大小的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个区块,第一个区块是队列,第二个区块是用户分配的,第三个区块仍旧空的。
  5. E
    演示了队列删除之后,存储空间也自动释放了。现在用户分配的区块两边都是空闲区块。
  6. F
    演示了用户分配的积存空间释放的意况。这么些区块现在和两边的空闲区块拼接成了一个更大的空闲区块。

Heap_4并不是总而言之的,可是要比正规库函数实现的malloc()free()运转的更快。

接轨都是一文山会海FreeRTOS相关的小说,先把FreeRTOS“圣经”Mastering the FreeRTOS Real Time kernel -- A Hands On Tutorial Guide 20161204卓绝研读,接连的多少个小说都是本身从这本“圣经”中翻译出来的。翻译难免存有疏漏、词不平易,我们凑合着看吗。

设定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演示的是IAR编译器把数组放在内存相对地址0x20000000上。

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

Listing 2

uint8_t ucHeap [configTOTAL_HEAP_SIZE] @ 0x20000000;

Listing 3

范围

本章节从业于让读者长远领悟:

  • FreeRTOS何时分配RAM
  • FreeRTOS 提供的5种内存分配方案
  • 采用哪种内存分配方案

从FreeRTOS
V9.0.0发端FreeRTOS应用程序可以完全用静态分配内存,而从不必要引入堆内存管理。

因为品种需要,目前开头攻读FreeRTOS,一着手有点令人不安,因为两个礼拜在此以前对于FreeRTOS的熟悉度几乎为零,经过对FreeRTOS官网的事例程序的搜寻,和体系中问题的化解,境遇了很多耳熟能详的人影,以前在Linux平台编程的阅历给了自我有的非凡实惠的经历,后悔当初没能在率先家商厦待下去,浪费了大好时光。好啊,现在仍旧潜下心来搞搞FreeRTOS吧。

动态内存分配的可选项

从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的涉嫌

从FreeRTOS
V9.0.0方始根本对象既可以在编译的时候静态分配,也得以在运行时动态分配。
本书随后的章节将会介绍以下基本对象:tasks,
queues, semaphoresevent
groups
。为了尽量让FreeRTOS易于使用,这一个基础对象并不是在编译时静态分配的,而是在运转时动态分配的。内核对象成立时FreeRTOS分配RAM而在基本对象删除时释放内存。这样的政策裁减了规划和计划上的用力,简化了API,并且缩短了RAM的挤占。

动态内存分配是C语言编程的定义,而不是针对性FreeRTOS或者多任务编程的概念。它和FreeRTOS是不无关系的,因为基本对象是动态分配的,并且通用编译器提供的动态内存分配方案对于实时应用程序并不总是适合的。

内存能够采用标准C库的malloc()free()函数来分配,但有可能不合乎,或者适当,因为下几点原因:

  • 在小型嵌入式系统中并不连续可用的
  • 它们的贯彻可能这么些的大,占据了非凡大的一块代码空间
  • 她们几乎都不是线程安全的
  • 它们并不是确定的,每便调用这个函数执行的刻钟也许都不雷同
  • 它们有可能暴发碎片
  • 它们有可能打乱链接器的部署
  • 假使同意堆空间的生长方向覆盖任何变量占据的内存,它们会成为debug的灾难

Malloc 失败钩子函数

应用程序可以一直调用pvPortMalloc()。当然在FreeRTOS源文件中每当内核对象成立时也会调用那一个函数。此类的木本对象包括任务,队列,信号量和事件组。

和正规库函数malloc()一样,如果pvPortMalloc()因为申请RAM的尺寸不可能满意没能重返一块RAM上空就会回去NULL。假如编程人员调用pvPortMalloc()来创制基础对象,可是回到NULL就表达内核对象没有创制成功。

事例中的所有堆分配方案都足以给pvPortMalloc()部署一个钩子函数(也称作回调函数),当pvPortMalloc()返回NULL时调用这个钩子函数。

比方文件FreeRTOSConfig.h中的configUSE_MALLOC_FAILED_HOOK设置为1,那么应用程序必须提供一个内存分配失利时的钩子函数,它的名字和原型参见如下。只要对这一个应用来说是适宜的,这一个钩子函数能够用此外措施来促成。

void vApplicationMallocFailedHook( void );