UC/OS-II 内存管理
1. 简介
uC/OS-II 不使用ANSI编译器的malloc(), free(),因为内存碎片,很可能获取不到一块连续的内存, 这在嵌入式系统中是很危险的。同时malloc()和free()的执行时间也是不确定的。
uC/OS-II 把内存划分为固定长度的块,一定数量的块组成一个partition,分配和回收的函数的执行时间是固定的,即常量时间。
可以有一个或多个分区(partition), 每个分区的块大小可以不一样,这样想获取不同size的块,就从不同的分区取。再者,从哪个分区获取的块,回收时要重新放回获取内存时的分区,即哪来哪去。
2. 数据结构
内存控制块:用于跟踪内存分区,每个分区使用自己的内存控制块
typedef struct { void *OSMemAddr; void *OSMemFreeList; INT32U OSMemBlkSize; INT32U OSMemNBlks; INT32U OSMemNFree; } OS_MEM;
OSMemAddr : 内存分区的起始地址,分区建立时初始化,以后不再改变
OSMemFreeList : 指针,两种用途:1.指向下一个空闲的内存控制块,2.指向下一个空闲的内存块,视情况定 ** 要注意区分内存控制块和内存块**
OSMemBlkSize : 分区中内存块的大小
OSMemNBlks : 分区内内存块总数,分区建立时指定
OSMemNFree : 内存块的可用数,就是还剩多少个块可以分配。
两个选项:(OS_CFG.H)
OS_MEM_EN 1 允许初始化内存管理器
OS_MAX_MEM_PART 4 内存分区数,至少是2
图:
这个链表由OSMemInit()建立,而OSMemInit()由OSInit()自动调用
3. 建立分区
分区要先初始化才能使用, 建立分区由OSMemCreate()完成:
OS_MEM OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err);
算法描述:
1. nblks >=2, blksize > sizeof(void *), 否则报错,返回(OS_MEM *)0;
2. 从OSMemFreeList取下一个内存控制块。因为一个分区需要一个内存控制块。
验证一下不是空指针
** OSMemFreeList 是个全局变量 **, 指向上面图中的内存控制块链表头
3. 将内存块连接起来,形成分区
4. 初始化2中取出的内存控制块
简单点说, 这个函数的功能就是把空闲的内存块连接起来形成分区,再将分区相关信息放入内存控制块。
代码这里就不粘出来了。 函数执行后, 内存分区如图:
值得注意的是,这些内存块是通过每个块的前面几个字节作为连接地址的。这就是为什么blksize > sizeof(void *)
4. 获取内存块
void * OSMemGet(OS_MEM *pmem, INT8U *err) ;
这个函数就是把内存控制块的OSMemFreeList所指向的内存块返回,然后OSMemFreeList(这个不是全局变量那个)指向下一个空闲内存块。
5. 返还内存块
INT8U OSMemPut(OS_MEM *pmem, void * pblk);
用完了就返还内存块到链表里。 返还的位置还是OSMemFreeList.
6. 获取内存分区的状态
INT8U OSMemQuery(OS_MEM *pmem, OS_MEM_DATA *pdata);
状态用一个结构来表示:
typedef struct { void *OSAddr; /* 分区的起始地址 */ void *OSFreeList; /* 空闲块的起始地址 */ INT32U OSBlkSize; /* 内存块的size */ INT32U OSNBlks; /* 分区里块的总数 */ INT32U OSNFree; /* 空闲块的数量 */ INT32U OSNUsed; /* 使用块的数量 */ } OS_MEM_DATA;
将内存控制块的各字段,赋给OS_MEM_DATA的各字段,很简单。