UCOSIII存储管理

来源:互联网 发布:js点击按钮弹出输入框 编辑:程序博客网 时间:2024/05/21 23:49
作为一个操作系统,内存管理是其必备的功能,在UCOSIII中也有内存管理模块,使用内存管理模块可以动态的分配和释放内存,这样可以高效的使用“昂贵”的内存资源内存管理简介内存管理是一个操作系统必备的系统模块,我们在用VC++或者Visual Studio学习C语言的时候会用malloc()和free()这两个函数来申请和释放内存。我们使用Keil MDK编写STM32程序的时候就可以使用malloc()和free(),但是不建议这么用,这样的操作会将原来大块的内存逐渐的风格成很多个小块内存,产生大量的内存碎片,最终到时应用不能申请到大小合适的连续内存。UCOSIII提供了自己的动态内存方案,其将存储空间分配为区和块,一个存储区有数个固定大小的库组成![存储区和存储块](http://img.blog.csdn.net/20160810155014452)一般存储区是固定的,在程序中可以用数组来表示一个存储区,比如u8 buffer[20][10]就表示一个有20个存储块,每个存储块10字节的存储区。如果我们定义的存储区在程序运行期间都不会被删除,一直有效,那么存储区内存也可以使用malloc()来分配。在创建存储区以后应用程序就可以获得固定大小的存储块。在实际使用中我们可以根据应用程序对内存需求的不同建立多个存储区,每个存储区中有不同大小、不同数量的存储块,应用程序可以根据所需内存不同从不同的存储区中申请内存使用,使用完以后在释放到相应的存储区中。存储区创建在使用内存管理之前首先要创建存储区,在创建存储区之前我们先了解一个重要的结构体,存储区控制块:OS_MEM,结构体OS_MEM如下,取掉了与调试有关的变量:

struct os_mem
{
OS_OBJ_TYPE Type; //类型,必须为OS_OBJ_TYPE_MEM
void *AddrPtr; //指向存储区起始地址
CPU_CHAR *NamePtr; //指向存储区名字
void *FreeListPtr; //指向空闲存储块
OS_MEM_SIZE BlkSize; //存储区中存储块大小,单位:字节
OS_MEM_QTY NbrMax; // 存储区中总的存储块数
OS_MEM_QTY NbrFree;// 存储区中空闲存储区中空闲存储块数
};
创建存储区使用函数OSMemCreate()函数用于创建一个存储区,函数参数如下:
p_mem: 指向存储区控制块地址,一般有用户程序定义个OS_MEM结构体 。
p_name: 指向存储区的名字,我们可以给存储区取一个名字。
p_addr: 存储区所有存储空间基地址。
n_blks : 存储区中块个数。
blk_size: 存储块大小。
p_err: 返回的错误码。

(1) 判断OSIntNestingCtr是否大于0如果大于0的话说明在中断调用函数 OSMemCreate()来创建存储区,如果是在中断调用函数 来创建存储区,如果是在中断调用函数 来创建存储区,如果是在中断调用函数OSMemCreate()将会返回错误码: OS_ERR_MEM_CREATE_ISR ,说明中断是不能调用函数OSMemCreate()来创建存储区的。(2)存储区空间基地址不能为0,否则地址无效,返回错误码OS_ERR_MEM_INVALID_P_ADDR 。(3)存储区中块数量 n_blks 最少为 2。(4)每个存储块大小不于一指针,在Keil MDK 中一个指针大小为4字节,因此每个 存储块大小要于4字节。(5)判断存储区空间基地址是否4字节对齐,存储区的空间基地址必须4字节对齐。 字节对齐。(6)存储区中每个块的大小要是4的倍数!(7) ~(14)将存储区中的块连成一个空闲存储块链表。每个存储块中保存着下一个储 块的地址,因此在(4)中规定了每个存储块要大于4个字节,因为每存储块至少要保一地 址,而一个地恰为4字节。(15)空闲存储块链表中最后一个指向0。(16)~(22)初始化结构体OS_MEM中的成员变量。(23)创建存储区成功以后,记录存储区数量的全局变OSMemQty加1调用函数OSMEMCreate()创建好的存储区如下所示。![创建好的存储区](http://img.blog.csdn.net/20160810161820836)存储块的使用调用函数OSMemCreate()创建好存储区以后我们就可以使用创建好的存储块了。内存申请使用函数OSMemGet()来获取存储块,函数原型如下:void *OSMemGet (OS_MEM *p_mem,                OS_ERR *p_err)函数OSMemGet()用来从指定的存储区中获取存储块共应用使用。p_mem:要使用的存储区。p_err: 返回的错误码。返回值:获取到的存储块地址。OSMemGet()函数过程如下:(1) 判断存储区p_mem是否存在,不存在的话就返货错误码:OS_ERR_MEM_INVALID_P_MEM 。(2) 判断存储区中是否还有空闲的存储块,没有话就返回错误码:OS_ERR_MEM_NO_FREE_BLKS 。(3)如果还有剩余存储块的话就取出空闲存储块链表中第一个存储块供用户程序使用。(4)在(3)中我们已经用掉了空闲存储块链表中的第一个存储块,那么空闲存储块链表头FreeListPtr就需要更新,指向下一个存储块。(5)因为应用程序申请了一个存储块,所以剩余数量减。(6)向应用程序返回申请到的存储块。从上面的分析中我们可以看出UCOSIII自带的内存管理函数局限性,每次申请时候用户要先估计所申请的内存是否会超过储区中块大小。比如我们创建了一个有10个存储块,每大小为 100 字节的存储区 buffer 。这时我们应用程序需要申请一个10字节的内存,那么就可以使用函数OSMemGet()从存储区buffer中申请一个存储块。但是每个存储块有 100 个字节,但是应用程序只使其中的10个字节,剩余的 90 个字节就浪费掉了,为了减少浪费我们可以创建一个每存储块为10字节的存储区,这样就不会有内费了。但是,问题又来了,假设我们在程序的其他地方需要申请一个150字节的内存,但是储区buffer的每个存储块只有100字节,显然存储区 buffer 不能满足程序的需求。有读者就会问可不以在存储区中连续申请两个100字节的存储块,这样就有200字节的内存供应用程序使用了?想法是好,但通过阅读函数OSMemGet () 发现并没有提供这样的功能,OSMemGet()函数在申请内存的时候每次只取指定存储区一个存储块!如果想150字节的内存就必须再新建一个每个存储块至少有150字节的存储区。通过上面的分析可以看出UCOSIII的内存管理很粗糙,不灵活并能申请指定大小的内 很粗糙,不灵活并不能申请指定大小的内存块。使用过LIENTEK的STM32开发板的用户就会知道ALIENTEK也实现了内存的动态使用,可以申请任意大小的内存空间使用起来十分方便。内存释放在UCOSIII中内存的释放可以使用函数OSMemPut()来完成,函数原型如下:void OSMemPut (OS_MEM     *p_mem,                void       *p_blk,                OS_ERR     *p_err)函数OSMemPut()用于释放内存,将申请到的存储块还给指定的存储区。    p_mem:指向存储区控制块,也就是要接收的那个。    p_blk: 指向存储块,要归还的。    p_err: 错误码。函数OSMemPut()过程如下:(1)检查存储区是否在,不存在的话就返回错误码: OS_ERR_MEM_INVALID_P_MEM 。(2)检查存储块是否在,不存在的话就返回错误码:OS_ERR_MEM_INVALID_P_BLK 。(3)检查存储区空闲块数量是否大于总存储块数量,如果大于的话就返回错误码: OS_ERR_MEM_FULL 。(4)将要归还的存储块添加到空闲链表中,这里是头位置,前面我们说了存储块中会保下一个空闲存储块的地址,所以这里向p_blk 中写入下一个空闲存储块地址。(5)将归还的存储块添加到空闲链表中以后需要更新一下  FreeListPtr 。(6)存储区中可用的存储块数量加1
1 0