FreeRTOS实时操作系统的内存管理分析

目录
  • 1.heap_1.c
    • 功能简介:
  • 2.heap_2.c
    • 功能简介:
  • 3.heap_3.c
    • 功能简介:
  • 4.heap_4.c
    • 功能简介:
  • 5.heap_5.c(V8.1.0新增)

前言

本文介绍内存管理的基础知识,详细源码分析见《 FreeRTOS内存管理示例分析》

FreeRTOS提供了几个内存堆管理方案,有复杂的也有简单的。其中最简单的管理策略也能满足很多应用的要求,比如对安全要求高的应用,这些应用根本不允许动态内存分配的。

FreeRTOS也允许你自己实现内存堆管理,甚至允许你同时使用两种内存堆管理方案。同时实现两种内存堆允许任务堆栈和其它RTOS对象放置到快速的内部RAM,应用数据放置到低速的外部RAM。

每当创建任务、队列、互斥量、软件定时器、信号量或事件组时,RTOS内核会为它们分配RAM。标准函数库中的malloc()和free()函数有些时候能够用于完成这个任务,但是:

  • 在嵌入式系统中,它们并不总是可以使用的;
  • 它们会占用更多宝贵的代码空间;
  • 它们没有线程保护;
  • 它们不具有确定性(每次调用执行的时间可能会不同);

因此,提供一个替代的内存分配方案通常是必要的。

嵌入式/实时系统具有千差万别的RAM和时间要求,因此一个RAM内存分配算法可能仅属于一个应用的子集。

为了避免这个问题,FreeRTOS在移植层保留内存分配API函数。移植层在RTOS核心代码源文件之外(不属于核心源代码),这使得不同的应用程序可以提供适合自己的应用实现。当RTOS内核需要RAM时,调用pvPortMallo()函数来代替malloc()函数。当RAM要被释放时,调用vPortFree()函数来代替free()函数。

FreeRTOS下载包中提供5种简单的内存分配实现,本文稍后会进行描述。用户可以适当的选择其中的一个,也可以自己设计内存分配策略。

FreeRTOS提供的内存分配方案分别位于不同的源文件(heap_1.c、heap_2.c、heap_3.c、heap_4.c、heap_5.c)之中,源文件位于下载包\FreeRTOS\Source\portable\MemMang文件夹中。其它实现方法可以根据需要增加。如果要使用FreeRTOS提供的内存堆分配方案,选中的源文件必须被正确的包含到工程文件中。

1.heap_1.c

这是所有实现中最简单的一个。一旦分配内存之后,它甚至不允许释放分配的内存。尽管这样,heap_1.c还是适用于大部分嵌入式应用程序。这是因为大多数深度嵌入式(deeplyembedded)应用只是在系统启动时创建所有任务、队列、信号量等,并且直到程序结束都会一直使用它们,永远不需要删除。

当需要分配RAM时,这个内存分配方案只是简单的将一个大数组细分出一个子集来。大数组的容量大小通过FreeRTOSConfig.h文件中的configTOTAL_HEAP_SIZE宏来设置。

API函数xPortGetFreeHeapSize()返回未分配的堆栈空间总大小,可以通过这个函数返回值对configTOTAL_HEAP_SIZE进行合理的设置。

功能简介:

  • 用于从不会删除任务、队列、信号量、互斥量等的应用程序(实际上大多数使用FreeRTOS的应用程序都符合这个条件)
  • 执行时间是确定的并且不会产生内存碎片
  • 实现和分配过程非常简单,需要的内存是从一个静态数组中分配的,意味着这种内存分配通常只是适用于那些不进行动态内存分配的应用。

2.heap_2.c

和方案1不同,这个方案使用一个最佳匹配算法,它允许释放之前分配的内存块。它不会把相邻的空闲块合成一个更大的块(换句话说,这会造成内存碎片)。

有效的堆栈空间大小由位于FreeRTOSConfig.h文件中的configTOTAL_HEAP_SIZE宏来定义。

API函数xPortGetFreeHeapSize()返回剩下的未分配堆栈空间的大小(可用于优化设置configTOTAL_HEAP_SIZE宏的值),但是不能提供未分配内存的碎片细节信息。

功能简介:

可以用于重复的分配和删除具有相同堆栈空间的任务、队列、信号量、互斥量等等,并且不考虑内存碎片的应用程序。

不能用在分配和释放随机字节堆栈空间的应用程序

  • 如果一个应用程序动态的创建和删除任务,并且分配给任务的堆栈空间总是同样大小,那么大多数情况下heap_2.c是可以使用的。但是,如果分配给任务的堆栈不总是相等,那么释放的有效内存可能碎片化,形成很多小的内存块。最后会因为没有足够大的连续堆栈空间而造成内存分配失败。在这种情况下,heap_4.c是一个很好的选择。
  • 如果一个应用程序动态的创建和删除队列,并且在每种情况下队列存储区域(队列存储区域指队列项数目乘以每个队列长度)都是同样的,那么大多数情况下heap_2.c可以使用。但是,如果队列存储区在每种情况下并不总是相等,那么释放的有效内存可能碎片化,形成很多小的内存块。最后会因为没有足够大的连续堆栈空间而造成内存分配失败。在这种情况下,heap_4.c是一个很好的选择。
  • 应用程序直接调用pvPortMalloc() 和 vPortFree()函数,而不仅是通过FreeRTOS API间接调用。

如果你的应用程序中的队列、任务、信号量、互斥量等等处在一个不可预料的顺序,则可能会导致内存碎片问题,虽然这是小概率事件,但必须牢记。

不具有确定性,但是它比标准库中的malloc函数具有高得多的效率。

heap_2.c适用于需要动态创建任务的大多数小型实时系统(smallreal time)。

3.heap_3.c

heap_3.c简单的包装了标准库中的malloc()和free()函数,包装后的malloc()和free()函数具备线程保护。

功能简介:

  • 需要链接器设置一个堆栈,并且编译器库提供malloc()和free()函数。
  • 不具有确定性
  • 可能明显的增大RTOS内核的代码大小

注:使用heap_3时,FreeRTOSConfig.h文件中的configTOTAL_HEAP_SIZE宏定义没有作用。

4.heap_4.c

这个方案使用一个最佳匹配算法,但不像方案2那样。它会将相邻的空闲内存块合并成一个更大的块(包含一个合并算法)。

有效的堆栈空间大小由位于FreeRTOSConfig.h文件中的configTOTAL_HEAP_SIZE来定义。

API函数xPortGetFreeHeapSize()返回剩下的未分配堆栈空间的大小(可用于优化设置configTOTAL_HEAP_SIZE宏的值),但是不能提供未分配内存的碎片细节信息。

功能简介:

  • 可用于重复分配、删除任务、队列、信号量、互斥量等等的应用程序。
  • 可以用于分配和释放随机字节内存的情况,并不像heap_2.c那样产生严重碎片。
  • 不具有确定性,但是它比标准库中的malloc函数具有高得多的效率。

heap_4.c还特别适用于移植层代码,可以直接使用pvPortMalloc()和 vPortFree()函数来分配和释放内存。

5.heap_5.c(V8.1.0新增)

这个方案同样实现了heap_4.c中的合并算法,并且允许堆栈跨越多个非连续的内存区。

Heap_5通过调用vPortDefineHeapRegions()函数实现初始化,在该函数执行完成前不允许使用内存分配和释放。创建RTOS对象(任务、队列、信号量等等)会隐含的调用pvPortMalloc(),因此必须注意:使用heap_5创建任何对象前,要先执行vPortDefineHeapRegions()函数。

vPortDefineHeapRegions()函数只需要单个参数。该参数是一个HeapRegion_t结构体类型数组。HeapRegion_t在portable.h中定义,如下所示:

  typedef struct HeapRegion
  {
      /* 用于内存堆的内存块起始地址*/
      uint8_t *pucStartAddress;  

      /* 内存块大小 */
      size_t xSizeInBytes;
  } HeapRegion_t;

这个数组必须使用一个NULL指针和0字节元素作为结束,起始地址必须从小到大排列。下面的代码段提供一个例子。MSVCWin32模拟器演示例程使用了heap_5,因此可以当做一个参考例程。

 /* 在内存中为内存堆分配两个内存块.第一个内存块0x10000字节,起始地址为0x80000000,
 第二个内存块0xa0000字节,起始地址为0x90000000.起始地址为0x80000000的内存块的
 起始地址更低,因此放到了数组的第一个位置.*/
 const HeapRegion_t xHeapRegions[] =
 {
     { ( uint8_t * ) 0x80000000UL, 0x10000 },
     { ( uint8_t * ) 0x90000000UL, 0xa0000 },
     { NULL, 0 } /* 数组结尾. */
 };
 /* 向函数vPortDefineHeapRegions()传递数组参数. */
 vPortDefineHeapRegions( xHeapRegions ); 

以上就是FreeRTOS实时操作系统的内存管理分析的详细内容,更多关于FreeRTOS内存管理的资料请关注我们其它相关文章!

(0)

相关推荐

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

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

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

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

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

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

  • FreeRTOS实时操作系统内核配置说明

    目录 1.configUSE_PREEMPTION 2.configUSE_PORT_OPTIMISED_TASK_SELECTION 3.configUSE_TICKLESS_IDLE 4.configUSE_IDLE_HOOK 5.configUSE_MALLOC_FAILED_HOOK 6.configUSE_TICK_HOOK 7.configCPU_CLOCK_HZ 8.configTICK_RATE_HZ 9.configMAX_PRIORITIES 10.configMINIMAL

  • FreeRTOS编码标准及风格指南

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

  • FreeRTOS实时操作系统的内存管理分析

    目录 1.heap_1.c 功能简介: 2.heap_2.c 功能简介: 3.heap_3.c 功能简介: 4.heap_4.c 功能简介: 5.heap_5.c(V8.1.0新增) 前言 本文介绍内存管理的基础知识,详细源码分析见< FreeRTOS内存管理示例分析> FreeRTOS提供了几个内存堆管理方案,有复杂的也有简单的.其中最简单的管理策略也能满足很多应用的要求,比如对安全要求高的应用,这些应用根本不允许动态内存分配的. FreeRTOS也允许你自己实现内存堆管理,甚至允许你同时使

  • FreeRTOS实时操作系统的任务创建和删除

    目录 前言 1.任务创建 1.1函数描述 1.2参数描述 1.3返回值 1.4用法举例 2.任务删除 2.1任务描述 2.2参数描述 前言 在FreeRTOS移植到Cortex-M3硬件平台的文章中,我们已经见过任务创建API,但那篇文章的重点在于如何移植FreeRTOS,本文将重点放在任务的创建和删除API函数上面. 任务创建和删除API函数位于文件task.c中,需要包含task.h头文件. 1.任务创建 1.1函数描述 BaseType_t xTaskCreate( TaskFunctio

  • FreeRTOS实时操作系统的任务应用函数详解

    目录 1.获取任务系统状态 1.1函数描述 1.2参数描述 1.3返回值 1.4用法举例 2.获取当前任务句柄 2.1函数描述 2.2返回值 3.获取空闲任务句柄 3.1函数描述 3.2返回值 4.获取任务堆栈最大使用深度 4.1函数描述 4.2参数描述 4.3返回值 4.4用法举例 5.获取任务状态 5.1函数描述 5.2参数描述 5.3返回值 6.获取任务描述内容 6.1函数描述 6.2参数描述 6.3返回值 7.获取系统节拍次数 7.1函数描述 7.2返回值 8.获取调度器状态 8.1函数

  • FreeRTOS实时操作系统的任务通知方法

    目录 前言 1.发送通知-方法1 1.1函数描述 1.2参数描述 1.3返回值 2.发送通知-方法2 2.1函数描述 2.2参数描述 2.3用法举例 3.获取通知 3.1函数描述 3.2参数描述 3.3返回值 4.等待通知 4.1函数描述 4.2参数描述 4.3返回值 4.4用法举例 5.任务通知并查询 5.1函数描述 5.2参数描述 5.3返回值 前言 注:本文介绍任务通知的基础知识,详细源码分析见FreeRTOS进阶<FreeRTOS高级篇8---FreeRTOS任务通知分析> 每个RTO

  • FreeRTOS实时操作系统的任务概要讲解

    目录 1. 任务和协程(Co-routines) 1.1任务的特性 1.2任务概要 2. 任务状态 3.任务优先级 4.实现一个任务 5.空闲任务和空闲任务钩子(idle task和Idle Task hook) 5.1空闲任务 5.2空闲任务钩子 1. 任务和协程(Co-routines) 应用程序可以使用任务也可以使用协程,或者两者混合使用,但是任务和协程使用不同的API函数,因此在任务和协程之间不能使用同一个队列或信号量传递数据. 通常情况下,协程仅用在资源非常少的微处理器中,特别是RAM

  • C语言动态内存管理分析总结

    目录 什么是动态内存分配 动态内存函数的介绍 free malloc calloc realloc 动态内存管理中常见的错误 对NULL指针的解引用操作 对动态开辟空间的越界访问 对非动态开辟内存使用free释放 使用free释放一块动态开辟内存的一部分 对同一块动态内存多次释放 动态开辟内存忘记释放(内存泄漏) 一些经典的笔试题 题目1 题目2 题目3 题目4 柔性数组 柔性数组的特点 柔性数组的优势 什么是动态内存分配 我们都知道在C语言中,定义变量的时候,系统就会为这个变量分配内存空间,而

  • FreeRTOS实时操作系统的多优先级实现

    目录 如何实现任务多优先级 软件通用方法和硬件指令方法 如何实现任务多优先级 FreeRTOS中,数字优先级越小,逻辑优先级也越小,空闲任务优先级为0.List_t pxReadyTasksLists[configMAX_PRIORITIES]是数组,数组下标代表任务优先级,任务创建是根据设置的任务优先级插入到对应下标的列表根节点上,如下. 要支持多优先级,就是再任务切换时让pxCurrentTCB指向最高优先级的TCB即可,之前时手动再任务1.任务2来回切换,现在问题就是怎么找到优先级最高的就

  • FreeRTOS实时操作系统的任务创建与任务切换

    目录 任务控制块数据结构 任务创建函数 定义就绪表 就绪表初始化 启动调度器 任务切换 任务控制块数据结构 任务控制块数据结构在task.c声明 typedef struct tskTaskControlBlock { volatile StackType_t * pxTopOfStack; //栈顶指针 ListItem_t xStateListItem; //任务节点 StackType_t * pxStack; //任务栈起始地址 char pcTaskName[configMAX_TAS

  • FreeRTOS实时操作系统的列表与列表项操作示例

    目录 前言 列表项数据结构 列表项初始化 列表数据结构 将列表项按照升序排列插入到列表 将列表项从列表删除 前言 FreeRTOS列表与列表项其实就是链表和节点,在list.c和list.h实现 列表项数据结构 //列表项数据结构 typedef struct xLIST_ITEM { TickType_t xItemValue; //辅助值,用作节点做顺序排序 struct xLIST_ITEM * pxNext;//后继指针 struct xLIST_ITEM * pxPrevious;//

  • FreeRTOS实时操作系统的内核控制示例解析

    目录 前言 1.强制上下文切换宏 2.进入临界区宏 3.退出临界区宏 4.禁止可屏蔽中断宏 5.使能可屏蔽中断宏 6.启动调度器 6.1函数描述 7.停止调度器 7.1函数描述 8.挂起调度器 8.1函数描述 9.恢复被挂起的调度器 9.1函数描述 9.2返回值 9.3用法举例 10.调整系统节拍 10.1函数描述 10.2参数描述 10.3用法举例 前言 内核控制的一些功能需要移植层提供,为了方便移植,这些API函数用宏来实现,比如上下文切换.进入和退出临界区.禁止和使能可屏蔽中断.内核控制函

随机推荐