UCOS-III 内存管理

01. 为什么不使用动态内存分配?

1)由于分配算法的复杂度及堆空间的使用情况,内存分配的时间具有不确定性。

2)在不断进行的内存分配及释放的过程中,产生内存碎片,导致可分配的内存变少

因此UCOS实现了自己的内存管理方式,以解决malloc方式进行动态内存分配的碎片化内存分配时间不确定的问题。

02. ucos 内存管理的使用

2.1 创建并初始化内存分区

1) 定义一块静态内存以及一个内存分区控制块(OS_MEM)
2) 调用OSMemCreate() 将分配的静态内存组织成一个单向链表,并将指向链表开头的指针存储在 OS_MEM 结构中。

OS_MEM       MyPartition;                                    
CPU_INT08U   MyPartitionStorage[12][100];                   
void  main (void)                                           
{
    OS_ERR  err;
    :
    :
    OSInit(&err);
    :
    OSMemCreate((OS_MEM    *)&MyPartition,                   
                (CPU_CHAR  *)"My Partition",                
                (void      *)&MyPartitionStorage[0][0],     
                (OS_MEM_QTY ) 12,                            
                (OS_MEM_SIZE)100,                           
                (OS_ERR    *)&err);                          
    /* Check 'err' */
}

 

d7cc622a096872957e9ea9b8968e83e2.png

2.2 从内存分区获取内存块

1)调用OSMemGet(),从内存分区中获取一个内存块,返回已配内存块的指针
2)必须检查返回的错误代码,以确保调用OSMemGet成功
OS_MEM       MyPartition;                                               
CPU_INT08U  *MyDataBlkPtr;
 void  MyTask (void *p_arg) 
{
    OS_ERR  err;
        MyDataBlkPtr = (CPU_INT08U *)OSMemGet((OS_MEM    *)&MyPartition,   
                                              (OS_ERR    *)&err);
        if (err == OS_ERR_NONE) {                                          
             /* You have a memory block from the partition */
        }

}

2.3 把内存块放回内存分区

1)调用OSMemPut(),把内存块放入内存分区中
2)必须检查返回的错误代码,以确保调用OSMemPut成功
OS_MEM       MyPartition;                                                  
CPU_INT08U  *MyDataBlkPtr;
 
 
void  MyTask (void *p_arg) 
{
    OS_ERR  err;
 
        OSMemPut((OS_MEM  *)&MyPartition,                                 
                 (void    *)MyDataBlkPtr,                                 
                 (OS_ERR  *)&err);
        if (err == OS_ERR_NONE) {                                          
             /* You properly returned the memory block to the partition */
        }
}

03. ucos 内存管理的实现

3.1 OS_MEM 内存分区控制块

struct os_mem {                                          
    CPU_CHAR            *NamePtr;
    void                *AddrPtr;      /* Pointer to beginning of memory partition               */
    void                *FreeListPtr;  /* Pointer to list of free memory blocks                  */
    OS_MEM_SIZE          BlkSize;      /* Size (in bytes) of each block of memory                */
    OS_MEM_QTY           NbrMax;       /* Total number of blocks in this partition               */
    OS_MEM_QTY           NbrFree;      /* Number of memory blocks remaining in this partition    */
};

3.2 创建内存分区

p_mem  应用程序定义的内存分区控制块指针,通过mallo分区或静态分配
p_name 内存分区的名称
p_addr  内存分区的起始地址
n_blks   内存块的数量
blk_size 内存块的大小
p_err    错误代码指针
void  OSMemCreate (OS_MEM       *p_mem,
                   CPU_CHAR     *p_name,
                   void         *p_addr,
                   OS_MEM_QTY    n_blks,
                   OS_MEM_SIZE   blk_size,
                   OS_ERR       *p_err)
{


    OS_MEM_QTY     i;
    OS_MEM_QTY     loops;
    CPU_INT08U    *p_blk;
    void         **p_link;
    CPU_SR_ALLOC();
    p_link = (void **)p_addr;        /* Create linked list of free memory blocks             */
    p_blk  = (CPU_INT08U *)p_addr;
    loops  = n_blks - 1u;


    for (i = 0u; i < loops; i++) {
        p_blk +=  blk_size;
       *p_link = (void  *)p_blk;           /* Save pointer to NEXT block in CURRENT block          */
        p_link = (void **)(void *)p_blk;   /* Position     to NEXT block                           */
    }


   *p_link             = (void *)0;    /* Last memory block points to NULL                     */


    CPU_CRITICAL_ENTER();
    p_mem->AddrPtr     = p_addr;      /* Store start address of memory partition              */
    p_mem->FreeListPtr = p_addr;      /* Initialize pointer to pool of free blocks            */
    p_mem->NbrFree     = n_blks;      /* Store number of free blocks in MCB                   */
    p_mem->NbrMax      = n_blks;
    p_mem->BlkSize     = blk_size;    /* Store block size of each memory blocks               */
    CPU_CRITICAL_EXIT();
   *p_err = OS_ERR_NONE;
}

3.3 从内存分区获取内存块

p_mem  应用程序定义的内存分区控制块指针
p_err    错误代码指针
void  *OSMemGet (OS_MEM  *p_mem,
                 OS_ERR  *p_err)
{
    void    *p_blk;
    CPU_SR_ALLOC();
    CPU_CRITICAL_ENTER();
    if (p_mem->NbrFree == 0u) {                    /* See if there are any free memory blocks              */
        CPU_CRITICAL_EXIT();
       *p_err = OS_ERR_MEM_NO_FREE_BLKS;           /* No,  Notify caller of empty memory partition         */
        return ((void *)0);                        /* Return NULL pointer to caller                        */
    }

    p_blk              = p_mem->FreeListPtr;    // 从空闲内存块链表的表头取出一个内存块         
    p_mem->FreeListPtr = *(void **)p_blk;       //空闲内存块链表指针指向下一个内存块

    //空闲内存块减一             
    p_mem->NbrFree--;                                         
    CPU_CRITICAL_EXIT();
   *p_err = OS_ERR_NONE;                    /* No error                                             */
    return (p_blk);                        /* Return memory block to caller                        */

3.4 把内存块放回内存分区

p_mem  应用程序定义的内存分区控制块指针
p_blk    内存块指针
p_err    错误代码指针
void  OSMemPut (OS_MEM  *p_mem,
                void    *p_blk,
                OS_ERR  *p_err)
{
    CPU_SR_ALLOC();
    CPU_CRITICAL_ENTER();
    if (p_mem->NbrFree >= p_mem->NbrMax) {           
        CPU_CRITICAL_EXIT();
       *p_err = OS_ERR_MEM_FULL;
        return;
    }
      //把内存块插入空闲内存块链表表头
    *(void **)p_blk    = p_mem->FreeListPtr;                 
    p_mem->FreeListPtr = p_blk;     
    //空闲内存块加一
    p_mem->NbrFree++;                                         
    CPU_CRITICAL_EXIT();
   *p_err              = OS_ERR_NONE;       
}

04. ucos内存管理的优缺点

优点:内存分配速度快,没有内存碎片

缺点: 一次只能分配一块固定大小的内存,内存分配灵活性差

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TechIoT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值