本文和大家分享的主要是UCOS中的內(nèi)存管理相關(guān)內(nèi)容,一起來看看吧,希望對大家學(xué)習(xí)ucos有所幫助。
在 嵌 入 式設(shè)備中,持續(xù)的調(diào)用malloc()和free()容易產(chǎn)生內(nèi)存碎片,長時間的運行最終會導(dǎo)致內(nèi)存消耗殆盡。UCOS提供了一套內(nèi)存管理機制,在系統(tǒng)初始化的時候就分配好內(nèi)存空間,將所有可用的空間組織成鏈表,需要申請內(nèi)存的時候直接從鏈表中申請,釋放內(nèi)存的時候直接將內(nèi)存歸還到空余內(nèi)存鏈表中即可。使用這種方法不僅避免了內(nèi)存碎片的產(chǎn)生,而且使得在常數(shù)時間內(nèi)分配內(nèi)存空間成為可能。
UCOS中內(nèi)存管理的結(jié)構(gòu)體是OS_MEM,具體結(jié)構(gòu)如下:
typedef struct os_mem //內(nèi)存控制塊{
void *OSMemAddr; //指向內(nèi)存分區(qū)的首地址
void *OSMemFreeList; //該內(nèi)存分區(qū)的block鏈表的表頭
INT32U OSMemBlkSize; //每一個block的大小
INT32U OSMemNBlks; //該分區(qū)中block的數(shù)目
INT32U OSMemNFree; //該分區(qū)中空閑block的數(shù)目
} OS_MEM;
在UCOS中,一個內(nèi)存分區(qū)被劃分成很多個大小相等的內(nèi)存塊,這些內(nèi)存塊鏈接成鏈表,鏈表的表頭存于OSMemFreeList中。
比如一個有4個內(nèi)存塊,每個內(nèi)存塊128bit的內(nèi)存分區(qū)Memoy如下:
INT32U Memory[4][4]
UCOS的思路是我們將要分配的空間組織成二維數(shù)組,然后二維數(shù)組的每一行就是一個block,二維數(shù)組的列數(shù)既是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
最終結(jié)果如下圖:
UCOS中創(chuàng)建內(nèi)存分區(qū)的核心代碼如下(代碼取自OSMemCreate):
//內(nèi)存分區(qū)的首地址
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組織成了一條鏈表。
申請一個內(nèi)存塊:
//還有內(nèi)存可以分配
if (pmem->OSMemNFree > 0)
{
//獲取一個block
pblk = pmem->OSMemFreeList;
//使鏈表表頭指向這個block的下一個block
pmem->OSMemFreeList = *(void **)pblk;
//更新內(nèi)存塊的數(shù)量
pmem->OSMemNFree--;
}
代碼的核心就在于pmem->OSMemFreeList = *(void **)pblk; 因為pblk指向該block,該block的首地址存放的是下一個block的地址,所以這句實際上讓空余鏈表的表頭指向了下一個block。
刪除一個內(nèi)存塊:
//在將要刪除的內(nèi)存塊的首地址存放block表頭的地址
*(void **)pblk = pmem->OSMemFreeList;
//更新鏈表表頭
pmem->OSMemFreeList = pblk;
//更新可用內(nèi)存塊的數(shù)目
pmem->OSMemNFree++;
代碼的核心就是*(void **)pblk = pmem->OSMemFreeList;在將要刪除的block的開頭存放鏈表的表頭,即相當(dāng)于把這個block鏈接到了空余鏈表的表頭中。
來源:CSDN