uC/OS II内存管理 详细分析

uC/OS II内存管理 详细分析
     RTOS最关键的特性就是实时性,那么,在开始的开始,RTOS中每个模块(任务->函数)的执行时间都应该是可以预见的,而传统的malloc和free函数的执行时间是不确定的,所以基本上所有的RTOS都实现了自已的内存管理算法,下面对uC/OS II 的内存管理进行详细的分析一下,看它是怎么来实现的。
   一、RTOS内存管理的概念
    1. 内存控制块OS_MEM
   uC/OS II对内存实行两级管理,即把一个连续的内存空间(通常是静态大数组)分为若干个区,每个分区又分为若干个大小相等(定长管理)的内存块。操作系统以分区为单位来管理动态内存,而任务以内存块为单位来获得和释放动态内存。内存分区和内存块的使用情况则由内存控制块来记录。
    2. 内存块
   uC/OS II 以内存块为单位向应用程序提供动态内存,内存块的大小由用户自定义。
    3. 内存分区
    大小相等的多个内存块可以组成一个内存分区。内存分区是系统对内存进行管理的基本单位,在内存中定义一个内存分区及其内存块的方法非常简单。定义一个二维数组即可,像下面这样:  
   INT16U   IntMemBuf[10][10]       // IntMemBuf实质上是指向内存分区的指针
    以上定义了一个内存分区,他包含10个内存块,每个内存块的长度为10,用来存储10个INT16U 类型的数据。
需要注意的是,上面的定义只是在内存中划分出了分区即内存块区域,还不是一个真正的可以动态分配的内存区。
实际上,在嵌入式系统中编写程序时,手动申请一个超级大的数组,然后把它交给系统内存控制块来管理,有需要时就申请,用完后就归还,从而对有限的内存区域重复使用。

    只有如下图把内存控制块与分区关联起来之后,系统才能对其进行相应的管理和控制,他才是一个真正的可以动态分配内存的区域。
    uC/OS II内存管理 详细分析_第1张图片
    内存控制块OS_MEM的结构:
    为了使系统能够感知和有效地管理内存分区,uC/OS II定义了一个叫做内存控制块的数据结构。系统就用这个内存控制块来记录和跟踪每一个内存分区的状态,数据结构类型如下:
typedef struct{
    void *OSMemAddr;               //内存分区的指针
    void *OSMemFreeList;           //内存控制块链表指针
    INT32U  OSMemBlkSize;          //内存块长度
    INT32U  OSMemNBlks;            //分区内存块的数目
    INT32U  OSMemFree;             //分区内当前可分配的内存块的数目
} OS_MEM;
   4. 空内存控制块链表
    uC/OS II初始化时,会调用内存控制块的初始化函数OS_MemIint()定义并初始化一个空内存控制块链表,在这个空内存控制块链表中,一共有OS_MAX_MEM_PART(在文件OS_CFG.H中定义)个空内存控制块。这些空内存控制块的指针成员OSMemFreeList暂时作为指向下一个空内存控制块的指针,这样所有的内存控制块链表如下图所示:
uC/OS II内存管理 详细分析_第2张图片

    每当应用程序需要创建一个内存分区时,系统就会从空内存控制块链表中摘取一个控制块,而把链表的头指针OSMemFreeList指向下一个空内存控制块;而每当应用程序释放一个内存分区时,则会把该分区对应的内存控制块归还给空内存控制块链表。

二、 动态内存管理的实现
    1. 创建内存分区
                  uC/OS II内存管理 详细分析_第3张图片
    OSMemCreate函数执行流程如下:
uC/OS II内存管理 详细分析_第4张图片

    这一系列的条件判断中有两个问题需要注意:
    1.分区中的内存块至少是两块,要不谈不上管理。
    2.每个内存块的中间中至少能存放一个指针,因为要在内存块中建立一个用于把分区内的内存块链接为一个链表的指针。
    在接下来的工作中,OSMemCreate()主要做了三个工作:
    首先自空内存控制块链表中取一个控制块;
    然后把分区内的内存控制块链接成链表建立内存分区;
    最后再把刚建立的内存分区的相关信息填入内存控制块,并返回与这个刚建立的内存分区相关联的内存控制块指针,以作为其他内存管理函数调用时的参数。
uC/OS II内存管理 详细分析_第5张图片

    1. 申请一个内存块  
/* 从pmem内存控制块中申请一个内存块,申请成功返回内存块的地址 */
void *MemGet(OS_MEM * pmem,  INT8U * err)
    函数执行流程如下:
uC/OS II内存管理 详细分析_第6张图片

    函数OSMemGet()在判断应用程序传递来的内存控制块的指针非NULL及内存分区尚存在未被分配的内存块后,就将内存块链表的第一个块地指针OSMemFreeList赋给了指针pblk;然后就重新调整内存块链表,并使指针OSMemFreeList指向新的链表头;然后返回pblk。
    需要注意的是,应用程序在调用函数OSMemGet()时,应该事先知道该分区中内存块的大小,并且在使用时不能超过该内存块的长度,否则会引起灾难性后果。从这一点可以看出,ucos的内存管理还是很粗糙,因为对一个完善的操作系统来说上述问题完全应该由操作系统添加一些内存边界检查之类的代码来解决,而不应该推给用户。

    2. 释放一内存块
INT8U  OSMemPut( OS_MEM  *pmem,  void  *pblk) // 将pblk指向的内存块归还到pmem指向的内存分区中
    需要注意的是,在调用OSMemPut()的一个内存块时,一定要确保把该内存块释放到它原来所属的内存分区中,否则会引发灾难性后果
   



你可能感兴趣的:(μC/OS,II,的那些事)