您现在的位置是:首页 > 单片机

嵌入式系统内存管理方案研究

2020-01-06 11:47:14

摘要:嵌入式系统的内存管理机制必须满足实时性和可靠性的要求。本文以开源的的操作系统RTEMS为例,介绍嵌入式系统中内存管理的要求、存在的问题以及解决的策略。

引言

内存管理机制是嵌入式系统研究中的一个重点和难点的问题,它必须满足以下几个特性:

①实时性。从实时性的角度出发,要求内存分配过程要尽可能地快。因此,在嵌入式系统中,不可能采用通用操作系统的一些复杂而完善的内存分配策略,一般没有段页式的虚存管理机制;而是采用简单、快速的内存分配方案,其分配方案也因程序对实时性的要求而异。例如,VxWorks系统采用简单的“首次适应,立即聚合”方法;VRTX中采用多个固定尺寸存储块的binning方案。

②可靠性。嵌入式系统应用的环境千变万化,在有些特定情况下,对系统的可靠性要求极高,内存分配的请求必须得到满足,如果分配失败则可能会带来灾难性的后果。比如,飞机的燃油检测系统。在飞机飞行过程中,如果燃料发生泄漏,系统应该立即检测到,并发出相应的警报等待飞行员及时处理。如果因为内存分配失败而不能相应地操作,就可能发生机毁人亡的事故。

③高效性。内存分配要尽可能地减少浪费。不可能为了保证满足所有的内存分配请求而将内存配置得很大。一方面,嵌入式系统对成本的要求使得内存在其中只是一种很有限的资源;另一方面,即使不考虑成本的因素,系统硬件环境有限的空间和有限的板面积决定了可配置的内存容量是很有限的。

针对以上三个约束条件,市场上主流的嵌入式操作系统,如VxWorks、嵌入式Linux等均提出了一套有效的解决方案;但是,这些系统只提供了应用开发的接口,其底层的实现方案不可见。本文以开源的嵌入式操作系统RTEMS为例,分析了嵌入式系统内存管理所面临的问题,研究了其底层实现的解决方案。一般的嵌入式系统中最基本的内存管理方案有两种——静态分配和动态分配。

1 静态分配与动态分配

静态分配是指在编译或链接时将程序所需的内存空间分配好。采用这种分配方案的程序段,其大小一般在编译时就能够确定;而动态分配是指系统运行时根据需要动态地分配内存。这两种策略的选取一直是嵌入式系统设计中一个令人头痛的问题。

一般的嵌入式系统都支持静态分配,因为像中断向量表、操作系统映像这类的程序段,其程序大小在编译和链接时是可以确定的。而是否支持动态分配主要基于两个方面的考虑:首先是实时性和可靠性的要求,其次是成本的要求。对于实时性和可靠性要求极高的系统(硬实时系统),不允许延时或者分配失效,必须采用静态内存分配,如航天器上的嵌入式系统多采用静态内存分配。除了基于成本的考虑外,用于汽车电子和工业自动化领域的一些系统也没有动态内存分配,比如WindRiver著名的OSEKWorks系统。然而,仅仅采用静态分配,使系统失去了灵活性。必须在设计阶段就预先知道所需要的内存并对之作出分配;必须在设计阶段就预先考虑到所有可能的情况,因为一旦出现没有考虑到的情况,正在运行的系统就无法处理。这样的分配方案必然导致很大的浪费。因为内存分配必须按照最坏情况进行最大的配置,而实际运行时很可能只使用其中的一小部分;而且在硬件平台不变的情况下,不可能灵活地为系统添加功能,从而使得系统的升级变得困难。

虽然动态内存分配会导致响应和执行时间不确定、内存碎片等问题,但是它的实现机制灵活,给程序实现带来极大的方便,有的应用环境中动态内存分配甚至最必不可少的。比如,嵌入式系统中使用的网络协议栈,在特定的平台下,为了比较灵活地调整系统的功能,在系统中各个功能之间作出权衡,必须支持动态内存分配。例如,为了使系统能够及时地在支持的VLAN数和支持的路由条目数之间作出调整,或者为了使不同的版本支持不同的协议,类似于malloc和free这类的函数是必不可少的。

大多数的系统是硬实时和软实时综合。系统中的一部分任务有严格的时限要求,而另一部分只是要求完成得越快越好。按照RMS(Rate Monotonous Scheduling)理论,这样的系统必须采用抢先式任务调度;而在这样的系统中,就可以采用动态内存分配来满足部分对可靠性和实时性要求不高的任务。采用动态内存分配的最大好处就是给设计得很大的灵活性,可以方便地将原来运行于非嵌入式操作系统的程序移植到嵌入式系统中。

2 RTEMS内存管现机制

RTEMS(The Rael TIme ExecuTIve for MulTI-processor Systems)是一个基于多处理器的,能够运行在不同处理器平台上的嵌入式操作系统。其应用领域十分广泛,包括航空航天设备(导弹、飞机控制系统),网络设备(路由器、交换 机),掌上设备(电子阅读器、PDA)等。针对不同领域应用的需求差异,该系统的内存管理提供了比较完善的机制。同其它常见的嵌入式系统一样,RTEMS不支持虚拟存储管理,不支持复杂的段页式的保护机制,而采用线性编址方式,即逻辑地址和物理地址一一对应的平面模式,同时支持静态和动态两种管理模式。在系统正常运行时,内存中的映像如图1所示。

图1中假设内破大小为2MB。在特定的应用中,中断表和RTEMS的映像所占用的内存空间大小是个定值,采用静态的内存分配机制,在编译时就可以确定其大小。堆栈区和系统内存区则采取动态分配机制,在系统运行时可以根据需要自动调整其大小。

3 RTEMS动态内存管理

RTEMS动态内存管理机制提供两种分区机制,ParTItion和Region。

Partition分区管理用于固定大小内存块的分配,Region分区管理 用于可变大小内存块的分配。

3.1 固定长度分区管理

RTEMS定义的固定长度的分区(Partition)是一段连续的内存空间。它可以被划分成固定长度的内存块(buffer),允许应用在创建分区时配置分区的大小和内存块的大小,要求分区的大小是内存块的整数倍。例如,应用创建一个大小为1024字节的分区,内存块为256字节,如图2所示。

创建分区时,RTEMS根据分区和内存块的大小,形成一个空闲内存块的双向链表。当从分区中申请内存块时,按照空闲内存块链表的顺序分配。如果空闲空间不足,调用者不会被阻塞,而是获得一个空指针,以确保申请内存调用的时间确定性。释放内存块时,将该内存块挂在空闲内存块链表的链尾。分区被删除时将释放出这段连续的内存空间。

RTEMS的分区管理机制提供以下API:

rtems_partition_create 创建一个分区

rtems_partition_ident 获得分区标识号

rtems_partition_deldet1 删除一个分区

rtems_partition_get_buffer 申请一个内存块

rtems_partition_return_buffer 释放一个内存块

RTEMS的固定长度分区管理算法有以下特色:

①系统创建的分区数目可在运行时动态增减。

②内存块的控制结构所占用的内存空间在该内存块被分配出去时会变为可用空间,不会影响该内存块实际可用的大小;而在回收时控制块会自动生成,这一点使得分区管理的系统开销对用户的影响为零。

③在分区的内存块中还可以再定义分区,这就意味着内存块可以很容易地被分为子内存块,提高了分区管理的灵活性。

    3.2 可变长度分区管理

RTEMS定义的可变长度的分区(Region)是一段连续的、大小可配置的内存空间,可以被划分成很多大小不一的段(Segment)。创建分区时要指定一个分配单元,称为页。段的大小是页的倍数,如果应用程序在申请段时,给出的大小不是页的倍数,内核会将其调整为页的倍数。例如,应用从而大小为512个字节的分区中申请一个大小为700字节的段,那么,内核实际分配的段大小为1024字节。

创建Region分区时,RTEMS根据分区大小和页小建立分区的控制结构和段的控制结构。在创建之初,只有一个空闲段,其大小为分区的大小减去控制结构的内存开销。随着应用申请、释放段的操作不断进行,分区中形成用双向链表链接起来的空闲段链。当从分区中分配段时,依据首次适应算法(即第一个满足要求的空闲段就作为分配结果)查看空闲段链中是否存在合适的段。当把段释放回分区时,该段被挂在空闲段链的链尾,并且如果空闲段链中有与此段相邻的段,则将其合并成一个更大的空闲段。RTEMS在段的控制块中设置一个标志位表示其被使用的情况。标志位为1表示该段正被使用,标志位为0表示该段空闲。图3是一个分区中具有两个空闲段和一个正被使用的段的示例。

空闲段和已经使用段的控制结构有所不同,如图4所示。

RTEMS的分区管理机制提供以下API:

rtems_region_create 创建一个分区

rtems_region_ident 获得分区的标识

rtems_region_delete 删除一个分区

rtems_region_extend 扩展一个分区

rtems_region_get_segment 申请一个段

rtems_region_return_segment 释放一个段

RTEMS的可变长度分区管理算法有以下特色:

①系统创建的分区数目可在运行时动态增加;

②段的控制结构在该段被分配出去后会减小,而在回收到控制快会自动恢复大小。这一点使得分区管理的系统开销降低到最小;

③时应用程序发现一个分区的内存空间不够使用时,可以调用retms_region_extend函数(API)扩展该分区的大小。

④当程序要求从某个分区获取分段而未成功时,可以立即返回,也可以采取多种等待策略。等待策略包括优先级等待、FIFO等待。在FIFO等待策略中又可分为有限等待和无限等待。

在动态可变长度内存管理的基础上,RTEMS还提供了Malloc/free等标准的C函数。在使用Malloc/free等函数时应注意以下几个方面的限制:

①因为内存分区是一种临界资源,由信号量保护,使用Malloc会导致当前调用挂起,因此它不能用于中断服务程序。

②因为进行内存分配需要执行查找算法,其执行时间与系统当前的内存使用情况相关,具有不确定性,因此对于有规定时限的操作是不适宜的。

③由于采用简单的首次适应算法,容易导致系统中存在大量的内存碎片,降低内存使用效率和系统性能。

4 结论

为了使嵌入式系统能够在不同的平台上进行移植,使之使用与各种应用环境,嵌入式系统内存管理方案在充分考虑实时性、可靠性和高效性的基础上,应该提供比较丰富的管理机制。本文分析了嵌入式系统中内存管理的要求、存在的问题,介绍了静态和动态两种分配策略;以开源的RTEMS系统为例,介绍了嵌入式系统中常用的内存管理方法,并对各种方法的特点进行了阐述,在实际应用时,可根据需求作出相应的选择。