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