1.ucosii内存管理的简易原理
ucosii的内存管理,采用的是如下方式,先分成若干个partitions,每个partitions再分成若干个blocks,每个blocks可以划分成若干大小的blksize(ucosii中,对blocksize的缩写)。使用时,通常在task中定义一个局部二维数组作为内存管理的“载体”,这个局部二维数组就是1个partitions,数组的行数是blocks,数组的列数是blksize,局部二维数组完美契合了ucosii中内存管理的特性。
2.ucosii内存管理的代码分析
ucosii的内存管理中使用了二维指针来进行链表的构建,与“正常”的链表有点区别,本文对ucosii中的易混淆的点和重点进行分析。
(1)OSMemFreeList在内存管理的代码中用了“两次”?
在ucosii.h中,有如下定义:
OS_EXT OS_MEM *OSMemFreeList; /* Pointer to free list of memory partitions */
有如下声明
typedef struct os_mem { /* MEMORY CONTROL BLOCK */
void *OSMemAddr; /* Pointer to beginning of memory partition */
void *OSMemFreeList; /* Pointer to list of free memory blocks */
INT32U OSMemBlkSize; /* Size (in bytes) of each block of memory */
INT32U OSMemNBlks; /* Total number of blocks in this partition */
INT32U OSMemNFree; /* Number of memory blocks remaining in this partition */
#if OS_MEM_NAME_EN > 0u
INT8U *OSMemName; /* Memory partition name */
#endif
} OS_MEM;
二者的具体用法在(2)中详细分析,这里只要知道不要把它们混淆即可。
(2) partitions里,二维指针对于blocks空闲链表的构建
OS_MemInit中,
for (i = 0u; i < (OS_MAX_MEM_PART - 1u); i++) { /* Init. list of free memory partitions */
pmem = &OSMemTbl[i]; /* Point to memory control block (MCB) */
pmem->OSMemFreeList = (void *)&OSMemTbl[i + 1u]; /* Chain list of free partitions */
#if OS_MEM_NAME_EN > 0u
pmem->OSMemName = (INT8U *)(void *)"?";
#endif
}
pmem = &OSMemTbl[i];
pmem->OSMemFreeList = (void *)0;
OS_MEM中的OSMemFreeList用来链接free partitions,OSMemTbl是在ucosii中的一个数组,
OS_EXT OS_MEM OSMemTbl[OS_MAX_MEM_PART];/* Storage for memory partition manager */
数组中的每一个元素对应一个partitions并对其进行管理。
OSMemFreeList = &OSMemTbl[0]; /* Point to beginning of free list */
全局变量OSMemFreeList指向第一个partitions,即OSMemTbl[0]的地址。
OSMemCreate中,
plink = (void **)addr; /* Create linked list of free memory blocks */
pblk = (INT8U *)addr;
loops = nblks - 1u;
for (i = 0u; i < loops; i++) {
pblk += blksize; /* Point to the FOLLOWING block */
*plink = (void *)pblk; /* Save pointer to NEXT block in CURRENT block */
plink = (void **)pblk; /* Position to NEXT block */
}
*plink = (void *)0; /* Last memory block points to NULL
使用2级指针来构建一个单向链表,*plink保存的是下一个block的地址(注意该链表是partitions内部的,即blocks之间的空闲链表,而不是partitions与partitions之间的链表,partitions与partitions之间的空闲链表是通过OS_MEM中的OSMemFreeList进行链接的,OSMemTbl中的某个OS_MEM被使用后,该OS_MEM的OSMemFreeList就指向申请的内存,即在任务中定义的二维数组),见图示: