×
嵌入式 > 技术百科 > 详情

UCOSii(五)——内存管理

发布时间:2022-04-28 发布时间:
|

一、前言

在嵌入式系统中,时常会面临Ram受限的情况。所以用C lib里的,malloc()和 free()来申请和释放内存时,频繁的内存请求造成的内存碎片会对系统性能造成负面影响。Ucos的解决办法是为内存划分不同大小的内存区域,每个区域内有一定数量、相同大小的内存块。每次申请内存都必须要以一个内存块为单位,释放内存块时,该内存块会回到相应的内存分区。这样,确实,内存的碎片的问题得到了一定程度的解决。

然而,这意味着内存管理对编码的人来说,是不透明的。牺牲灵活性的代价就是用户必须提前根据自己的实际需要,把空闲内存划分成不同的内存分区,再把内存分区切割成几个相同大小的内存块。即使是在系统运行过程中的动态内存请求,编码的人也要提前为自己不同的任务分配内存区域和内存块。UCOS的使用者必须纵观整个项目,构建出最合适的memory map,才能高效使用ram资源。

二、内存控制块

MCB用来定义一个内存区域的属性。这种有点类似面向对象的控制结构在UCOSii里很常见,只要在Tcb、Ecb和Mcb这样的控制块中,加入一些方法,这个控制块瞬间就变成了一个类。只是出于实时性的需要,RTOS一般使用效率更高的结构性语言而经常与高级语言无缘,但UCOSii作者的设计思想依然很值得我们借鉴。

MCB原型:

typedef struct {    void *OSMemAddr;    void *OSMemFreeList;
    INT32U OSMemBlkSize;
    INT32U OSMemNBlks;
    INT32U OSMemNFree;
} OS_MEM;1234567

.OSMemAddr 是指向内存分区起始地址的指针。它在建立内存分区时被初始化,在此之后就不能更改了。

.OSMemFreeList 是指向下一个空闲内存控制块或者下一个空闲的内存块的指针。

.OSMemBlkSize和.OSMemNBlks 是内存分区中内存的总大小和内存块数量,是用户建立该内存分区时指定的。

.OSMemNFree 是内存分区中当前可以得空闲内存块数量。

不得不说这个数据结构十分简洁,减掉一个属性和加一个属性都显得没有必要。

三、相关函数

3.1 建立一个内存分区,OSMemCreate()

在建立一个内存分区前,用户需要自己先在全局定义好这个分区和一个内存控制块指针。

OS_MEM *CommTxBuf;
INT8U CommTxPart[100][32];12

然后将定义好的区域作为参数传给OSMemCreate(),使用指针接收函数的返回值。

CommTxBuf = OSMemCreate(CommTxPart, 100, 32, &err);1

这个函数最主要的功能,就是初始化一个Mcb结构。将起始地址、总大小、分块数量、初始空闲内存等等写入一个Mcb,然后这个Mcb的指针作为函数的返回值。之后对该块内存的申请、释放操作都将通过这个指针来进行,和Ecb完全一样。

这里值得一提的是空闲内存块表,它是一个指针单向链表,Freelist指向它的第一个元素。初始化代码如下:

    plink = (void **)addr;
    pblk = (INT8U *)addr + blksize;    for (i = 0; i 

为了修改指针的值,使用了二级指针。将一个二级指针指向的指针的值先修改成下一个内存块的起始地址,然后将该二级指针的指向下一个内存块的起始地址,然后循环,以此构建一个指针链表。最后一个指针指向NULL。

3.2 分配一个内存块,OSMemGet()

如果内存分区没有被申请完,OSMemGet()返回一个内存区域里的一个空闲块。将空闲链表里的第一个元素删除即可,其实就是修改.OSMemFreeList的向,将它指向空闲块链表第二个元素就OK。

3.3 释放一个内存块,OSMemPut()

释放内存时,OSMemPut()将改内存块的指针放回空闲队列。将.OSMemFreeList的值指向它,再将第一个元素指向原链表头。这样可以观察到,对于内存的动态申请和释放,UCOSii用的实际上是先进先出的策略。最后被释放的内存块将会最先被分配给申请者。

3.4 查询一个内存分区的状态,OSMemQuery()

返回Mcb当前的各种属性。

四、用信号量等待一块内存

UCOSii没有提供相应的机制,但可以用信号量模拟内存申请的等待,申请内存前先申请信号量。

例子:

for (;;) {
    OSSemPend(SemaphorePtr, 0, &err);
    pblock = OSMemGet(PartitionPtr, &err);  
    OSMemPut(PartitionPtr, pblock);
    OSSemPost(SemaphorePtr);
}



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
iPhone将是质的飞跃:苹果A14处理器+高通X55基带