應用程序中爲了某種特殊須要,常常須要動態的分配內存,而操做系統的特質置一,就是能不能保證動態內存分配的時效性,也就是說分配時間是可肯定的數組
Ucos提供內存分配功能,它將內存空間分爲兩級管理,將一塊連續的內存空間分爲若干個分區,每一個分區單位又分紅大小相同的若干個內存塊,分區時操做系統的管理單位,而內存塊是分配單位,內存分區以及內存塊的使用狀況有一個叫作內存控制塊的表來記錄,內存控制塊的基本結構以下函數
typedef struct os_mem { oop
void *OSMemAddr; 操作系統
void *OSMemFreeList; 指針
INT32U OSMemBlkSize; code
INT32U OSMemNBlks; blog
INT32U OSMemNFree; 接口
#if OS_MEM_NAME_EN > 0u內存
INT8U *OSMemName; 原型
#endif
} OS_MEM;
OSMemAddr 內存分區的指針
OSMemFreeList 內存控制塊鏈表的指針
OSMemBlkSize 內存塊的長度
OSMemNBlks 分區內內存塊的數目
OSMemNFree 分區內部當前可分配內存塊數目
系統在初始化的時候將當前系統內部的全部內存控制塊構成一個鏈表,叫作空閒內存控制塊表,變量以下
OS_EXT OS_MEM *OSMemFreeList;
而系統初始時刻存在的內存控制塊的數目是給定的
OS_EXT OS_MEM OSMemTbl[OS_MAX_MEM_PART];
OS_MAX_MEM_PART是一個宏,決定系統擁有幾個內存分區,在os_cfg.h文件中定義
初始化內存控制塊列表的函數爲OS_MemInit,其中的核心code爲
OS_MemClr((INT8U *)&OSMemTbl[0], sizeof(OSMemTbl));
for (i = 0u; i < (OS_MAX_MEM_PART - 1u); i++) {
pmem = &OSMemTbl[i];
pmem->OSMemFreeList = (void *)&OSMemTbl[i + 1u];
#if OS_MEM_NAME_EN > 0u
pmem->OSMemName = (INT8U *)(void *)"?";
#endif
}
pmem = &OSMemTbl[i];
pmem->OSMemFreeList = (void *)0;
#if OS_MEM_NAME_EN > 0u
pmem->OSMemName = (INT8U *)(void *)"?";
#endif
OSMemFreeList = &OSMemTbl[0];
相似於tcb初始化的流程,也是將一個數組鏈表化,而且將OSMemFreeList指向鏈表的開頭,此時系統是尚未開始管理內存的,由於咱們並無告訴系統咱們可分配的內存在哪裏,那在哪兒指明瞭呢,答案是在OSMemCreate中,該函數初始化一個內存分區,並返回一個內存分區控制結構體,函數原型以下
OS_MEM *OSMemCreate (void *addr,INT32U nblks,INT32U blksize,INT8U *perr)
指明咱們空閒內存分區的開始地址,咱們分配的內存塊的長度以及內存塊的數目,三者計算就能獲得咱們分配的內存大小nblks*blksize
在OSMemCreate中先作了如下操做
plink = (void **)addr;
pblk = (INT8U *)addr;
loops = nblks - 1u;
for (i = 0u; i < loops; i++) {
pblk += blksize;
*plink = (void *)pblk;
plink = (void **)pblk;
}
這句話實現的其實是將一個內存分區分解爲nblks個內存塊,而後在每個內存塊的最頭上位置放置了一個指針,這個指正指向下一個內存塊的首地址,用圖比較好解釋
如上就是基本的內存管理結構了
pmem->OSMemAddr = addr;
pmem->OSMemFreeList = addr;
pmem->OSMemNFree = nblks;
pmem->OSMemNBlks = nblks;
pmem->OSMemBlkSize = blksize;
接下來就是進行了內存控制塊的賦值操做,也就是說,ucos的兩級內存管理其實是經過兩級鏈表來操做的.空閒內存控制塊構成一個空閒鏈表,分配的內存塊有內存塊自己包含的指針造成單向鏈表,此時內存控制塊的指向爲可分配內存的頭
而向操做系統申請內存塊的函數爲OSMemGet,其核心流程代碼以下
if (pmem->OSMemNFree > 0u) {
pblk = pmem->OSMemFreeList;
pmem->OSMemFreeList = *(void **)pblk;
pmem->OSMemNFree--;
該函數須要咱們給出一個內存控制塊指針,函數從控制塊中返回空閒內存,首先檢測控制塊內是否還有空閒內存,如有,將最近的空閒內存返回,控制快內空閒內存-1, OSMemFreeList指向下一個空閒內存塊的首地址.
而釋放內存塊的操做使用OSMemPut完成,該函數接受兩個參數,一個是空閒內存控制塊的指針,一個是想要釋放的內存指針,核心代碼爲
*(void **)pblk = pmem->OSMemFreeList;
pmem->OSMemFreeList = pblk;
pmem->OSMemNFree++;
經過分析以上代碼能夠得出,新釋放的內存塊被插入到空閒塊的最頭上地址,控制塊中的空閒塊指針指向釋放的地址,釋放地址的首地址存放原來的第一個空閒塊的地址,鏈表恢復,並將空閒內存++;
另外能夠經過OSMemQuery查詢內存分區的狀態,簡單接口,再也不贅述
可是必定要注意,ucos的內存管理是存在問題的!
在OSMemCreate中有如下語句
INT8U *pblk;
這是一個八位指針,後面在進行內存塊劃分的時候有如下代碼
for (i = 0u; i < loops; i++) {
pblk += blksize;
可是pblk是8位的,最多隻能支持255內存管理,32位內存空間的話就不能用這個,因此32位尋址的時候,須要修改這部分的東西,我推薦這個部分的內存管理代碼能夠本身寫,反正和操做系統任務調度也沒有關係