首页 > 代码库 > UCOS学习之内存管理

UCOS学习之内存管理

本文和大家分享的主要是UCOS中的内存管理相关内容,一起来看看吧,希望对大家学习ucos有所帮助。

在 嵌 入 式设备中,持续的调用malloc()free()容易产生内存碎片,长时间的运行最终会导致内存消耗殆尽。UCOS提供了一套内存管理机制,在系统初始化的时候就分配好内存空间,将所有可用的空间组织成链表,需要申请内存的时候直接从链表中申请,释放内存的时候直接将内存归还到空余内存链表中即可。使用这种方法不仅避免了内存碎片的产生,而且使得在常数时间内分配内存空间成为可能。

UCOS中内存管理的结构体是OS_MEM,具体结构如下:

typedef struct os_mem  //内存控制块{

void   *OSMemAddr; //指向内存分区的首地址

void   *OSMemFreeList; //该内存分区的block链表的表头

INT32U  OSMemBlkSize;  //每一个block的大小

INT32U  OSMemNBlks; //该分区中block的数目

INT32U  OSMemNFree; //该分区中空闲block的数目

} OS_MEM;

UCOS中,一个内存分区被划分成很多个大小相等的内存块,这些内存块链接成链表,链表的表头存于OSMemFreeList中。

比如一个有4个内存块,每个内存块128bit的内存分区Memoy如下:

INT32U Memory[4][4]

UCOS的思路是我们将要分配的空间组织成二维数组,然后二维数组的每一行就是一个block,二维数组的列数既是block的大小。

Memory的第一个block的首地址是Memor[0]

Memory的第二个block的首地址是Memory[1]

Memory的第三个block的首地址是Memory[2]

Memory的第四个block的首地址是Memory[3]

为了管理方便我们在每一个block的开头存储下一个block的地址,这样就把所有的block串接成了单链表。

第一个block的开头存储Memory[1]

第一个block的开头存储Memory[2]

第一个block的开头存储Memory[3]

第一个block的开头存储NULL

最终结果如下图:


UCOS中创建内存分区的核心代码如下(代码取自OSMemCreate)

//内存分区的首地址

plink = (void **)addr;

//第二个block的地址

pblk  = (INT8U *)((INT32U)addr + blksize);

for (i = 0; i < (nblks - 1); i++)

{

//每一个block的开头存放下一个block的首地址

*plink = (void *)pblk;

//更新指针而已

plink = (void **)pblk;

pblk  = (INT8U *)((INT32U)pblk + blksize);

}

//最后一个block指向NULL

*plink  = (void *)0;

上述代码的核心就在于*pblink = (void*)pblk;每一个block开头存放下一个block的地址,这样便把所有的block组织成了一条链表。

申请一个内存块:

//还有内存可以分配

if (pmem->OSMemNFree > 0)

{

//获取一个block

pblk = pmem->OSMemFreeList;

//使链表表头指向这个block的下一个block

pmem->OSMemFreeList = *(void **)pblk;

//更新内存块的数量

pmem->OSMemNFree--;

}

代码的核心就在于pmem->OSMemFreeList = *(void **)pblk;  因为pblk指向该block,该block的首地址存放的是下一个block的地址,所以这句实际上让空余链表的表头指向了下一个block

删除一个内存块:

//在将要删除的内存块的首地址存放block表头的地址

*(void **)pblk  = pmem->OSMemFreeList;

//更新链表表头

pmem->OSMemFreeList = pblk;

//更新可用内存块的数目

pmem->OSMemNFree++;

代码的核心就是*(void **)pblk      = pmem->OSMemFreeList;在将要删除的block的开头存放链表的表头,即相当于把这个block链接到了空余链表的表头中。

 

 来源:CSDN

UCOS学习之内存管理