UC/OS II 内存管理

COSII 采用的是固定分区的方式管理内存。
将连续大块的内存按分区来管理,每个系统中若干个这样的分区,每个分区中又有若干个大小相同的内存块。
在进行内存分配的时候,根据需求从分区中得到几个内存块。而在释放的时候,内存块又重新返回所在的分区。

1:内存管理的数据结构
内存管理的数据结构包括有内存控制块(MCB),空闲内存控制块链表,内存分区等。
其定义如下:
typedef struct os_mem {                   /* MEMORY CONTROL BLOCK */
    void   *OSMemAddr;                    //内存分区的起始地址
    void   *OSMemFreeList;                //空闲块链表地址
    INT32U  OSMemBlkSize;                 //每个内存块的大小
    INT32U  OSMemNBlks;                   //内存块的数量
    INT32U  OSMemNFree;                   //空闲内存块的数量
#if OS_MEM_NAME_EN > 0u
    INT8U  *OSMemName;                    //名称
#endif
} OS_MEM;

内存控制块(MCB)是内存分区的核心数据块。每一个内存分区对应一个MCB。
MCB的实体在ucos_ii.h中定义全局变量,系统默认的数目是5个
#define OS_MAX_MEM_PART           5  
OS_EXT  OS_MEM            OSMemTbl[OS_MAX_MEM_PART]

所有的未用的MCB,都会链接在一个链表上,并且用OSMemFreeList指针指向该链表表头。

内存分区需要用户提供,一大块连续地址的内存。
通常我们只需要定义一个二维数组就可以了如 INT32U MemBuf[10][20],这个分区就是10*20*4=800字节大小的内存分区,分为10个内存块,每个内存块80个字节。

2:内存管理函数
内存管理函数主要有5个

2.1:内存控制块初始化OS_MemInit
在系统初始化调用OSInit的时候,若是配置内存管理模块,OSInit会调用OS_MemInit
该函数的主要功能是将所有内存控制块的数据清零,并且将所有MCB内存控制块连在空闲链表上。

2.2:创建内存分区OSMemCreate
内存分区在操作系统初始化的时候并不存在。在使用一个分区之前,必须先定义一个二维数组,但是这个二维数组还没有进行分区。
OSMemCreate就是使用一个MCB,对这个二维数组进行管理,形成一个分区。
函数的原型如下:OS_MEM  *OSMemCreate (void   *addr, INT32U  nblks, INT32U  blksize,INT8U  *perr)
addr是内存分区的首地址,nblk是分区数目,blksize是一个分区的大小,perr调用的过程的信息

其函数的主要实现代码如下:
//从空闲链表上取MCB
pmem = OSMemFreeList;                            
    if (OSMemFreeList != (OS_MEM *)0) {               /* See if pool of free partitions was empty      */
        OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList;
    }
    OS_EXIT_CRITICAL();
    if (pmem == (OS_MEM *)0) {                        /* See if we have a memory partition             */
        *perr = OS_ERR_MEM_INVALID_PART;
        return ((OS_MEM *)0);
    }
//开始进行分区管理
    plink = (void **)addr;                            //获取内存分区的首地址
    pblk  = (INT8U *)addr;                         //获取块的第一个地址
    loops  = nblks - 1u;
    for (i = 0u; i < loops; i++) {
        pblk +=  blksize;                             //pblk指向下一个内存块
       *plink = (void  *)pblk;                        //当前块的第一个元素中存储下一个块的地址
        plink = (void **)pblk;                        //plink指向下一个块
    }
    *plink              = (void *)0;                  //达到最后一个内存块
//根据分区数据,设置MCB
    pmem->OSMemAddr     = addr;                       /* Store start address of memory partition       */
    pmem->OSMemFreeList = addr;                       /* Initialize pointer to pool of free blocks     */
    pmem->OSMemNFree    = nblks;                      /* Store number of free blocks in MCB            */
    pmem->OSMemNBlks    = nblks;
    pmem->OSMemBlkSize  = blksize;                    /* Store block size of each memory blocks        */
    *perr               = OS_ERR_NONE;

2.3:内存分区的获取内存块OSMemGet
该函数的主要功能是通过已经创建的内存分区中获取内存块。若申请成功,则返回内存地址,若申请不成功,则返回空地址。
该函数的原型如下:void  *OSMemGet (OS_MEM  *pmem, INT8U   *perr)
其主要实现代码如下:
if (pmem->OSMemNFree > 0u) {                      //是否有空闲的内存块
        pblk                = pmem->OSMemFreeList;    //取空闲内存块链表的表头
        pmem->OSMemFreeList = *(void **)pblk;         
        pmem->OSMemNFree--;                           //空闲内存块数量减1
        OS_EXIT_CRITICAL();
        *perr = OS_ERR_NONE;                          /*      No error                                 */
        return (pblk);                                /*      Return memory block to caller            */
    }

2.4:释放内存块OSMemPut
当任务不在需要该内存块的时候,就将其归还给之前的内存分区。
函数原型如下 INT8U  OSMemPut (OS_MEM  *pmem, void    *pblk)  pblk为内存块的地址
if (pmem->OSMemNFree >= pmem->OSMemNBlks) {  //确保内存块没有全部释放掉,也即是说空闲快数量没有大于后者等于最大空闲快数量
        OS_EXIT_CRITICAL();
        return (OS_ERR_MEM_FULL);
    }
    *(void **)pblk      = pmem->OSMemFreeList;   //将内存块插入到链表表头
    pmem->OSMemFreeList = pblk;
    pmem->OSMemNFree++;     //空闲内存块的数量加1

2.5:查询分区状态OSMemQuery
该函数的原型如下:INT8U  OSMemQuery (OS_MEM       *pmem,  OS_MEM_DATA  *p_mem_data)
其主要功能是将分区当前的信息(都在MCB中),读取存入p_mem_data指向的结构体中。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值