0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

嵌入式操作系统FreeRTOS内存如何管理和堆

黄工的嵌入式技术圈 来源:黄工的嵌入式技术圈 作者:黄工的嵌入式技术 2020-01-10 15:17 次阅读

编辑:黄工 公众号:strongerHuang 素材来源:FreeRTOS网站 + 网络 前两年FreeRTOS被亚马逊收购之后,变化不大,应该是在规划物联网这一块。 前段时间FreeRTOS官网的界面发生了变化,接下来可能会有大的动作,感兴趣的朋友可以去看一下。 网址:

https://www.freertos.org

回读之前文章:谈谈FreeRTOS_V10版本FreeRTOS更新至V10.2.1 言归正传,回来说FreeRTOS的内存管理和堆的问题。从 V9.0.0 开始,FreeRTOS 应用程序可以完全静态分配,这意味着无需包含堆内存管理器。 FreeRTOS内存管理地址:
https://www.freertos.org/a00111.html 一、拓展知识动态内存分配及其与 FreeRTOS 的关联性:要让 FreeRTOS 对象(如任务、队列、信号量和事件组)变得尽可能易于使用,这些内核对象不是在编译时静态分配,而是在运行时动态分配。每次创建内核对象时,FreeRTOS 都会分配 RAM

每次删除内核对象时,都会释放 RAM。此策略可减少设计和规划工作量,简化了 API,并最大程度地减少 RAM 开销。

动态内存分配是一个 C 语言编程概念。它不是特定于 FreeRTOS 或多任务处理的概念。它与 FreeRTOS 相关,因为内核对象是动态分配的,通用编译器提供的动态内存分配方案并非始终适合实时应用程序。

可以使用标准 C 语言库函数 malloc() 和 free() 分配内存,但由于以下一个或多个原因,这些函数可能不适合或不适用:

•它们并非始终适用于小型嵌入式系统。•它们的实现可能相当大,占用宝贵的代码空间。•它们极少是线程安全的。•它们不是确定性的。执行函数所花的时间量将因调用不同而异。•它们可能会碎片化。如果堆中的可用 RAM 被拆分为若干较小且彼此分离的块,则认为堆已碎片化。当堆已碎片化时,如果堆中没有一个可用块的大小足以包含某个数据块,则尝试分配此数据块时将失败,即使堆中所有单独块的总大小比无法分配的数据块大小大很多倍,也是如此。•它们可能使链接器配置变得更复杂。•如果允许堆空间增长而占用了其他变量使用的内存,则这些函数可能成为一些难以调试的错误的来源。 二、动态内存分配的选项

早期版本的 FreeRTOS 使用内存池分配方案,在编译时预分配由不同大小的内存块组成的池,然后由内存分配函数返回。虽然这是实时系统中常用的方案,但它产生了大量支持请求。由于该方案使用 RAM 的效率无法满足非常小型的嵌入式系统的需要,因此已被放弃。

FreeRTOS 现在将内存分配视为可移植层的一部分(而不是核心代码库的一部分)。这样做的原因是我们已认识到嵌入式系统具有变化多端的动态内存分配和计时要求。单个动态内存分配算法仅适用于一部分应用程序。此外,通过从核心代码库中删除动态内存分配,应用程序编写者可以适时提供其自己的特定实现。

当 FreeRTOS 需要 RAM 时,它调用 pvPortMalloc() 而不是 malloc()。释放 RAM 时,内核调用 vPortFree(),而不是 free()。pvPortMalloc() 与标准 C 语言库函数 malloc() 具有相同的原型。vPortFree() 与标准 C 语言库函数 free() 具有相同的原型。

pvPortMalloc() 和 vPortFree() 是公共函数,因此,也可以从应用程序代码中调用它们。

FreeRTOS 附带了 pvPortMalloc() 和 vPortFree() 的五个示例实现,本指南将一一介绍。FreeRTOS 应用程序可以使用其中一个示例实现或提供自己的实现。

这五个示例在 heap_1.c、heap_2.c、heap_3.c、heap_4.c 和 heap_5.c 源文件中定义,这些源文件位于FreeRTOS/Source/portable/MemMang 目录中。

三、5种内存分配实现

heap_1:最简单,不允许释放内存。

heap_2:允许释放内存,但不能合并相邻的空闲块。

heap_3:简单包装标准的malloc()和free()以确保线程安全。

heap_4:合并相邻的空闲块以避免碎片。包括绝对地址放置选项。

heap_5:按照heap_4,具有跨多个不相邻的内存区域扩展堆的能力。

Heap_1

它常用于小型专用嵌入式系统,以便仅在启动计划程序之前创建任务和其他内核对象。在应用程序开始执行任何实时功能之前,内核动态分配内存,并且内存在应用程序的生命周期内保持已分配状态。这意味着所选分配方案不必考虑任何更复杂的内存分配问题(例如确定性和碎片化),而是可以考虑如代码大小和简单性等属性。

Heap_1.c 实现 pvPortMalloc() 的一个非常基本的版本。它不实现 vPortFree()。从不删除任务或其他内核对象的应用程序可以使用 heap_1。

某些商业关键和安全关键型系统可能禁止动态内存分配,这些系统也可能能够使用 heap_1。由于存在与非确定性、内存碎片化以及分配失败等相关的不确定性,因此,关键系统通常禁止动态内存分配,但 heap_1 始终是确定性的且无法对内存进行碎片化。

当调用 pvPortMalloc() 时,heap_1 分配方案将一个简单的数组细分成更小的块。此数组称为 FreeRTOS堆。

数组的总大小(以字节为单位)由定义 configTOTAL_HEAP_SIZE 在 FreeRTOSConfig.h 中设置。以这种方式定义大型数组可能让应用程序看起来会消耗大量 RAM,甚至从数组中分配任何内存之前就是如此。

每个创建的任务都要求从堆中分配一个任务控制块 (TCB) 和一个堆栈。

下图显示了在创建任务时 heap_1 如何细分简单的数组。每次创建任务时,都会从 heap_1 数组分配 RAM。

A 显示创建任何任务之前的数组。整个数组都可用。

B 显示已创建一个任务后的数组。

C 显示已创建三个任务后的数组。

Heap_2

Heap_2 包含在 FreeRTOS 发行版中以保持向后兼容性。建议不要用于新设计,而是考虑使用 heap_4,因为其中提供了更多功能。

也可以使用 Heap_2.c,但要细分由 configTOTAL_HEAP_SIZE 确定大小的数组。它使用最适合算法分配内存。与 heap_1 不同,它允许释放内存。再次说明,数组是静态声明的,因此应用程序看起来会消耗大量RAM,甚至在从数组中分配任何内存之前就是如此。

最适合算法可确保 pvPortMalloc() 使用的可用内存块在大小方面与所要求的字节数最接近。例如,考虑以下情形:

• 堆包含三个可用内存块,大小分别为 5 字节、25 字节和 100 字节。 • 调用 pvPortMalloc() 以请求 20 字节的 RAM。

适合所请求字节数的最小可用 RAM 块是 25 字节块,因此,pvPortMalloc() 将 25 字节块拆分成一个 20 字节块和一个 5 字节块,然后返回一个指向 20 字节块的指针。(上面是过于简化了,因为 heap_2 要存储堆区域中块大小的信息,因此两个拆分块的总和实际上将小于 25。) 新的 5 字节块保持可用于将来对pvPortMalloc() 的调用。

与 heap_4 不同,heap_2 不将相邻的可用块合并为单个更大的块。因此,它更容易碎片化。但是,如果分配的块与后续释放的块大小始终相同,则碎片化不是问题。Heap_2 适合反复创建和删除任务的应用程序,但前提是分配给所创建的任务的堆栈大小不发生变化。

下图显示在创建和删除任务时从 heap_2 数组中分配和释放 RAM 的过程。

图中显示当创建、删除以及后续再次创建任务时,最适合算法的工作原理

• A显示已创建三个任务后的数组。大型可用块保持在数组的顶部。

• B显示已删除其中一个任务后的数组。这些区域有:

数组顶部的大型可用块保持原样。此外,目前有两个较小的可用块,它们之前分配给了已删除任务的TCB 和堆栈。

• C显示已创建另一个任务后的数组。创建任务导致两次调用 pvPortMalloc():一次是分配新的 TCB,一次是分配任务堆栈。使用 xTaskCreate() API 函数创建任务,如创建任务 (p. 23)中所述。在 xTaskCreate() 内部发生两次 pvPortMalloc() 调用。

每个 TCB 的大小完全相同,因此,最适合算法可确保之前分配给已删除任务的 TCB 的 RAM 块可重用于分配新任务的 TCB。

分配给新创建任务的堆栈大小与分配给以前被删除任务的堆栈大小完全相同,因此,最适合算法可确保之前分配给已删除任务的堆栈的 RAM 块可重用于分配新任务的堆栈。

数组顶部的较大的未分配块保持不变。Heap_2 是非确定性的,但它比 malloc() 和 free() 的大多数标准库实现都要快。

Heap_3

Heap_3.c 使用标准库函数 malloc() 和 free(),因此堆大小由链接器配置定义。configTOTAL_HEAP_SIZE 设置不起作用。

Heap_3 通过临时暂停 FreeRTOS 计划程序使 malloc() 和 free() 成为线程安全的。

Heap_4

与 heap_1 和 heap_2 一样,heap_4 将数组细分成较小的块。数组是静态声明的并由configTOTAL_HEAP_SIZE 确定大小,因此应用程序看起来会消耗大量 RAM,甚至在从数组中分配任何内存之前就是如此。

Heap_4 使用首个适合算法分配内存。与 heap_2 不同,它会将相邻的可用内存块组合(合并)成一个较大的块。这样可以最大程度地减小内存碎片化风险。

首个适合算法可确保 pvPortMalloc() 使用第一个大小足以容纳所要求的字节数的可用内存块。例如,考虑以下情形:

• 堆包含三个可用内存块。它们在数组中以下面的顺序显示:5 字节、200 字节和 100 字节。 • 调用 pvPortMalloc() 以请求 20 字节的 RAM。

适合所请求字节数的第一个可用 RAM 块是 200 字节块,因此,pvPortMalloc() 将 200 字节块拆分成一个 20字节块和一个 180 字节块,然后返回一个指向 20 字节块的指针。(上面是过于简化了,因为 heap_4 要存储堆区域中块大小的信息,因此两个拆分块的总和将小于 200 字节。) 新的 180 字节块保持可用于将来对pvPortMalloc() 的调用。

Heap_4 会将相邻的可用内存块组合(合并)成一个较大的块,同时最大限度地降低碎片化风险。Heap_4 适用于反复分配和释放不同大小的 RAM 块的应用程序。

下图显示从 heap_4 数组中分配和释放 RAM 的过程。它演示 heap_4 首个适合算法(带内存合并)在分配和释放内存时的工作方式。

A显示已创建三个任务后的数组。大型可用块保持在数组顶部。

B显示已删除其中一个任务后的数组。

C显示已创建一个 FreeRTOS 队列后的数组。

D显示在从应用程序代码中直接调用 pvPortMalloc()(而不是通过间接调用 FreeRTOS API 函数)后的数组。

E显示删除队列后的数组,此时会自动释放分配给已删除队列的内存。此时,用户分配的块的两侧都有可用内存。

F显示的也是已释放用户分配的内存之后的数组。用户分配的块所用的内存已与两侧的可用内存组合成一个更大的可用块。

Heap_4 是非确定性的,但比 malloc() 和 free() 的大多数标准库实现都要快。

Heap_5

heap_5 用来分配和释放内存的算法与 heap_4 的完全相同。与 heap_4 不同,heap_5 不限于从单个静态声明的数组分配内存。Heap_5 可以从多个单独的内存空间分配内存。当运行 FreeRTOS 的系统提供的 RAM在系统的内存映射中未作为单个邻接的(没有空间)块出现时,Heap_5 很有用。

Heap_5 是唯一一个必须在调用 pvPortMalloc() 之前显式初始化的内存分配方案。它使用 vPortDefineHeapRegions() API 函数进行初始化。当使用 heap_5 时,必须先调用vPortDefineHeapRegions(),然后才可创建任何内核对象(任务、队列、信号等)。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式系统
    +关注

    关注

    41

    文章

    3550

    浏览量

    129088
  • 内存
    +关注

    关注

    8

    文章

    2962

    浏览量

    73803
  • FreeRTOS
    +关注

    关注

    12

    文章

    483

    浏览量

    61906
收藏 人收藏

    评论

    相关推荐

    嵌入式 Linux 操作系统配置

    随着物联网(IoT)和智能设备的快速发展,嵌入式系统在各个领域扮演着越来越重要的角色。Linux因其开源、灵活和稳定的特性,成为嵌入式系统的首选操作
    的头像 发表于 11-06 10:22 95次阅读

    【「嵌入式Hypervisor:架构、原理与应用」阅读体验】+ 了解Hypervisor

    : 浏览目录,其中包括中断隔离、分区引导、内存管理、分区通信、内核服务等关键字,这些不都属于操作系统的范围嘛!第一章开头一段就解开了我的疑惑:Hypervisor用于托管多个客户操作系统
    发表于 10-13 16:47

    freertos和rtos区别是什么

    (Real-Time Operating System,实时操作系统)是一种特殊的操作系统,它能够为实时任务提供确定性的响应时间。RTOS 通常用于嵌入式系统,如工业自动化、汽车电子、
    的头像 发表于 09-02 14:18 806次阅读

    嵌入式linux开发板怎么操作

    嵌入式Linux开发板是一种基于Linux操作系统嵌入式系统开发平台。它通常包括一个处理器、内存、存储器、输入/输出接口等硬件组件,以及一
    的头像 发表于 09-02 09:09 304次阅读

    RT-Thread出席第六届中国嵌入式技术大会,共话嵌入式操作系统与智能工业

    第六届中国嵌入式技术大会将于8月27-28日在深圳会展中心(福田)1号馆举行。本届大会以“AI与开源,开启嵌入式系统智能新时代”为主题,聚焦人工智能与嵌入式应用、
    的头像 发表于 08-03 08:35 343次阅读
    RT-Thread出席第六届中国<b class='flag-5'>嵌入式</b>技术大会,共话<b class='flag-5'>嵌入式</b><b class='flag-5'>操作系统</b>与智能工业

    第六届国产嵌入式操作系统技术与产业发展论坛议程发布

    每年一度的国产嵌入式操作系统论坛即将在杭州滨江举办,今年是第六届了,又是中国嵌入式系统新朋老友相聚的时刻。大模型催生AI走人千家万户、唤醒端侧AI的需求爆发。以机器人、无人驾驶和智能制
    发表于 07-26 10:54

    嵌入式系统怎么学?

    操作系统的基本概念和原理,掌握常见的RTOS,如FreeRTOS、uC/OS等,以实现对嵌入式系统的任务调度和资源管理。 6、通信协议:学
    发表于 07-02 10:10

    如何提升嵌入式编程能力?

    /C++:大多数嵌入式系统使用C或C++编程语言,因此深入学习这两种语言是非常重要的。 8. 理解操作系统:学习嵌入式操作系统(如
    发表于 06-21 10:01

    实时操作系统之RT-Thread及FreeRTOS

    RT-Thread与其他很多RTOS如FreeRTOS的主要区别之一是,它不仅仅是一个实时内核,还具备丰富的中间层组件,如下图所示。FreeRTOS和RT-Thread是两种常见的嵌入式实时
    的头像 发表于 05-29 08:10 3351次阅读
    实时<b class='flag-5'>操作系统</b>之RT-Thread及<b class='flag-5'>FreeRTOS</b>

    再谈嵌入式实时操作系统

    由于嵌入式处理器早期功能单一且运算能力不高,嵌入式应用已不能满足各个领域不断增长的需求。嵌入式操作系统应运而生,嵌入式
    的头像 发表于 04-09 17:27 710次阅读
    再谈<b class='flag-5'>嵌入式</b>实时<b class='flag-5'>操作系统</b>

    瑞萨CTSU程序在向嵌入式OS操作系统移植时的注意事项

    瑞萨CTSU程序在向嵌入式OS操作系统移植时的注意事项
    的头像 发表于 03-29 08:05 291次阅读
    瑞萨CTSU程序在向<b class='flag-5'>嵌入式</b>OS<b class='flag-5'>操作系统</b>移植时的注意事项

    FreeRTOS内存机制详解

    FreeRTOS是一种实时操作系统,它提供了多种内存分配方式,包括动态内存分配和静态内存分配。
    的头像 发表于 12-31 16:49 2442次阅读
    <b class='flag-5'>FreeRTOS</b><b class='flag-5'>内存</b>机制详解

    单片机操作系统有哪些

    FreeRTOSFreeRTOS是一种基于优先级的实时操作系统,广泛应用于嵌入式系统中。它具有小巧、高效、可移植的特点,并且支持多任
    的头像 发表于 12-08 16:18 4766次阅读

    FreeRTOS的发展历史和技术演进

    嵌入式系统的领域中,实时操作系统(RTOS)是非常重要甚至不可或缺的组成部分。FreeRTOS(Real-Time Operating System)是一款广泛使用的开源 RTOS,
    的头像 发表于 11-18 17:55 1645次阅读

    聊聊FreeRTOS内存管理方案及相关的优化措施

    FreeRTOS 作为一个嵌入式实时操作系统,其运行的环境一般资源有限
    的头像 发表于 11-13 11:28 925次阅读
    聊聊<b class='flag-5'>FreeRTOS</b><b class='flag-5'>内存</b><b class='flag-5'>管理</b>方案及相关的优化措施