详解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链接到了空余链表的表头中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值