μC/OS-II的內存管理
for(i=0;i(nblks-1);i++){
*plink=(void*)pblk;
plink=(void**)pblk;
pblk=pblk+blksize;
}
*plink=(void*)0;
OS_ENTER_CRITICAL();
pmem->OSMemAddr=addr;(6)
pmem->OSMemFreeList=addr;
pmem->OSMemNFree=nblks;
pmem->OSMemNBlks=nblks;
pmem->OSMemBlkSize=blksize;
OS_EXIT_CRITICAL();
*err=OS_NO_ERR;
return(pmem);(7)
}
圖F7.4是OSMemCreate()函數完成后,內存控制塊及對應的內存分區和分區內的內存塊之間的關系。在程序運行期間,經過多次的內存分配和釋放后,同一分區內的各內存塊之間的鏈接順序會發生很大的變化。
分配一個內存塊,OSMemGet()應用程序可以調用OSMemGet()函數從已經建立的內存分區中申請一個內存塊。該函數的唯一參數是指向特定內存分區的指針,該指針在建立內存分區時,由OSMemCreate()函數返回。顯然,應用程序必須知道內存塊的大小,并且在使用時不能超過該容量。例如,如果一個內存分區內的內存塊為32字節,那么,應用程序最多只能使用該內存塊中的32字節。當應用程序不再使用這個內存塊后,必須及時把它釋放,重新放入相應的內存分區中[見7.03節,釋放一個內存塊,OSMemPut()]。

圖F7.4OSMemCreate()——Figure7.4
程序清單L7.4是OSMemGet()函數的源代碼。參數中的指針pmem指向用戶希望從其中分配內存塊的內存分區[L7.4(1)]。OSMemGet()首先檢查內存分區中是否有空閑的內存塊[L7.4(2)]。
如果有,從空閑內存塊鏈表中刪除第一個內存塊[L7.4(3)],并對空閑內存塊鏈表作相應的修改[L7.4(4)]。這包括將鏈表頭指針后移一個元素和空閑內存塊數減1[L7.4(5)]。最后,返回指向被分配內存塊的指針[L7.4(6)]。
程序清單L7.4OSMemGet()
void*OSMemGet(OS_MEM*pmem,INT8U*err)(1)
{
void*pblk;
OS_ENTER_CRITICAL();
if(pmem->OSMemNFree>0){(2)
pblk=pmem->OSMemFreeList;(3)
pmem->OSMemFreeList=*(void**)pblk;(4)
pmem->OSMemNFree--;(5)
OS_EXIT_CRITICAL();
*err=OS_NO_ERR;
return(pblk);(6)
}else{
OS_EXIT_CRITICAL();
*err=OS_MEM_NO_FREE_BLKS;
return((void*)0);
}
}
值得注意的是,用戶可以在中斷服務子程序中調用OSMemGet(),因為在暫時沒有內存塊可用的情況下,OSMemGet()不會等待,而是馬上返回NULL指針。
釋放一個內存塊,OSMemPut()
當用戶應用程序不再使用一個內存塊時,必須及時地把它釋放并放回到相應的內存分區中。這個操作由OSMemPut()函數完成。必須注意的是,OSMemPut()并不知道一個內存塊是屬于哪個內存分區的。例如,用戶任務從一個包含32字節內存塊的分區中分配了一個內存塊,用完后,把它返還給了一個包含120字節內存塊的內存分區。當用戶應用程序下一次申請120字節分區中的一個內存塊時,它會只得到32字節的可用空間,其它88字節屬于其它的任務,這就有可能使系統崩潰。
程序清單L7.5是OSMemPut()函數的源代碼。它的第一個參數pmem是指向內存控制塊的指針,也即內存塊屬于的內存分區[L7.5(1)]。OSMemPut()首先檢查內存分區是否已滿[L7.5(2)]。如果已滿,說明系統在分配和釋放內存時出現了錯誤。如果未滿,要釋放的內存塊被插入到該分區的空閑內存塊鏈表中[L7.5(3)]。最后,將分區中空閑內存塊總數加1[L7.5(4)]。
程序清單L7.5OSMemPut()
INT8UOSMemPut(OS_MEM*pmem,void*pblk)(1)
{
OS_ENTER_CRITICAL();
if(pmem->OSMemNFree>=pmem->OSMemNBlks){(2)
OS_EXIT_CRITICAL();
return(OS_MEM_FULL);
}
*(void**)pblk=pmem->OSMemFreeList;(3)
pmem->OSMemFreeList=pblk;
pmem->OSMemNFree++;(4)
OS_EXIT_CRITICAL();
return(OS_NO_ERR);
}
查詢一個內存分區的狀態,OSMemQuery()
在μC/OS-II中,可以使用OSMemQuery()函數來查詢一個特定內存分區的有關消息。通過該函數可以知道特定內存分區中內存塊的大小、可用內存塊數和正在使用的內存塊數等信息。所有這些信息都放在一個叫OS_MEM_DATA的數據結構中,如程序清單L7.6。
程序清單L7.6OS_MEM_DATA數據結構
typedefstruct{
void*OSAddr;/*指向內存分區首地址的指針*/
void*OSFreeList;/*指向空閑內存塊鏈表首地址的指針*/
INT32UOSBlkSize;/*每個內存塊所含的字節數*/
INT32UOSNBlks;/*內存分區總的內存塊數*/
INT32UOSNFree;/*空閑內存塊總數*/
INT32UOSNUsed;/*正在使用的內存塊總數*/
}OS_MEM_DATA;
程序清單L7.7是OSMemQuery()函數的源代碼,它將指定內存分區的信息復制到OS_MEM_DATA定義的變量的對應域中。在此之前,代碼首先禁止了外部中斷,防止復制過程中某些變量值被修改[L7.7(1)]。由于正在使用的內存塊數是由 OS_MEM_DATA中的局部變量計算得到的,所以,可以放在(criticalsection中斷屏蔽)的外面。
程序清單L7.7OSMemQuery()
INT8UOSMemQuery(OS_MEM*pmem,OS_MEM_DATA*pdata)
{
OS_ENTER_CRITICAL();
pdata->OSAddr=pmem->OSMemAddr;(1)
pdata->OSFreeList=pmem->OSMemFreeList;
pdata->OSBlkSize=pmem->OSMemBlkSize;
pdata->OSNBlks=pmem->OSMemNBlks;
pdata->OSNFree=pmem->OSMemNFree;
OS_EXIT_CRITICAL();
pdata->OSNUsed=pdata->OSNBlks-pdata->OSNFree;(2)
return(OS_NO_ERR);
}
UsingMemoryPartitions
評論