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指向的結構體中。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章