当前位置:首页 > 嵌入式 > 技术让梦想更伟大
[导读]关注、星标公众号,直达精彩内容ID:技术让梦想更伟大整理:李肖遥内存管理对应用程序和操作系统来说都非常重要。现在很多的程序漏洞和运行崩溃都和内存分配使用错误有关。FreeRTOS操作系统将内核与内存管理分开实现,操作系统内核仅规定了必要的内存管理函数原型,而不关心这些内存管理函数...


关注、星标公众号,直达精彩内容

ID:技术让梦想更伟大

整理:李肖遥


内存管理对应用程序和操作系统来说都非常重要。现在很多的程序漏洞和运行崩溃都和内存分配使用错误有关。

FreeRTOS操作系统将内核与内存管理分开实现,操作系统内核仅规定了必要的内存管理函数原型,而不关心这些内存管理函数是如何实现的。

这样做大有好处,可以增加系统的灵活性:不同的应用场合可以使用不同的内存分配实现,选择对自己更有利的内存管理策略。

比如对于安全型的嵌入式系统,通常不允许动态内存分配,那么可以采用非常简单的内存管理策略,一经申请的内存,甚至不允许被释放。

在满足设计要求的前提下,系统越简单越容易做的更安全。

再比如一些复杂应用,要求动态的申请、释放内存操作,那么也可以设计出相对复杂的内存管理策略,允许动态分配和动态释放。

FreeRTOS内核规定的几个内存管理函数原型为:」

void *pvPortMalloc( size_t xSize ) :内存申请函数
void vPortFree( void *pv ) :内存释放函数
void vPortInitialiseBlocks( void ) :初始化内存堆函数
size_t xPortGetFreeHeapSize( void ) :获取当前未分配的内存堆大小
size_t xPortGetMinimumEverFreeHeapSize( void ):获取未分配的内存堆历史最小值
FreeRTOS提供了5种内存管理实现,有简单也有复杂的,可以应用于绝大多数场合。

它们位于下载包目录*...\FreeRTOS\Source\portable\MemMang*中,文件名分别为:heap_1.c、heap_2.c、heap_3.c、heap_4.c、heap_5.c。

我在《FreeRTOS系列第8篇---FreeRTOS内存管理》这篇文章中介绍了这5种内存管理的特性以及各自应用的场合,今天我们要分析它们的实现方法。

FreeRTOS提供的内存管理都是从内存堆中分配内存的。默认情况下,FreeRTOS内核创建任务、队列、信号量、事件组、软件定时器都是借助内存管理函数从内存堆中分配内存。

最新的FreeRTOS版本(V9.0.0及其以上版本)可以完全使用静态内存分配方法,也就是不使用任何内存堆。

对于heap_1.c、heap_2.c和heap_4.c这三种内存管理策略,内存堆实际上是一个很大的数组,定义为:

static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
其中宏configTOTAL_HEAP_SIZE用来定义内存堆的大小,这个宏在FreeRTOSConfig.h中设置。

对于heap_3.c,这种策略只是简单的包装了标准库中的malloc()和free()函数,包装后的malloc()和free()函数具备线程保护。因此,内存堆需要通过编译器或者启动文件设置堆空间。

heap_5.c比较有趣,它允许程序设置多个非连续内存堆,比如需要快速访问的内存堆设置在片内RAM,稍微慢速访问的内存堆设置在外部RAM。每个内存堆的起始地址和大小由应用程序设计者定义。

1. heap_1.c

这是5个内存管理策略中最简单的一个,我们称为第一个内存管理策略,它简单到只能申请内存。

是的,跟你想的一样,一旦申请成功后,这块内存再也不能被释放。

对于大多数嵌入式系统,特别是对安全要求高的嵌入式系统,这种内存管理策略很有用,因为对系统软件来说,逻辑越简单越容易兼顾安全。

实际上,大多数的嵌入式系统并不需要动态删除任务、信号量、队列等,而是在初始化的时候一次性创建好,便一直使用,永远不用删除。

所以这个内存管理策略实现简洁、安全可靠,使用的非常广泛。我对这个对内存管理策略也情有独钟。

我们可以将第一种内存管理看作是切面包:初始化的内存就像一根完整的长棍面包,每次申请内存,就从一端切下适当长度的面包返还给申请者,直到面包被分配完毕,就这么简单。

这个内存管理策略使用两个局部静态变量来跟踪内存分配,变量定义为:

static size_t xNextFreeByte = ( size_t ) 0;
static uint8_t *pucAlignedHeap = NULL;
其中,变量xNextFreeByte记录已经分配的内存大小,用来定位下一个空闲的内存堆位置。

因为内存堆实际上是一个大数组,我们只需要知道已分配内存的大小,就可以用它作为偏移量找到未分配内存的起始地址。

变量xNextFreeByte被初始化为0,然后每次申请内存成功后,都会增加申请内存的字节数目。

变量pucAlignedHeap指向对齐后的内存堆起始位置。「为什么要对齐?」

这是因为大多数硬件访问内存对齐的数据速度会更快。

为了提高性能,FreeRTOS会进行对齐操作,不同的硬件架构对齐操作也不尽相同,对于Cortex-M3架构,进行8字节对齐。

我们来看一下第一种内存管理策略对外提供的API函数。

1.1内存申请:pvPortMalloc()

「函数源码为:」

void *pvPortMalloc( size_t xWantedSize )
{
void *pvReturn = NULL;
static uint8_t *pucAlignedHeap = NULL;
 
    /* 确保申请的字节数是对齐字节数的倍数 */
    #if( portBYTE_ALIGNMENT != 1 )
    {
        if( xWantedSize 
本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭