




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
第9章內存管理9.1概述
9.2建立內存分區——OSMemCreate()9.3分配內存塊——OSMemGet()
9.4釋放內存塊——OSMemPut()
9.5查詢內存分區的狀態——OSMemQuery()習題
9.1概述
9.1.1基本原理
在內存管理方面,ANSIC本身就提供了malloc()和free()兩個函數用于動態地分配內存和釋放內存。但是,μC/OS-Ⅱ為什么不直接利用這兩個函數,而要另外構建內存管理方法呢,其主要原因在于以下兩個方面:
(1)當應用程序反復調用malloc()和free()函數進行內存的分配與釋放時,可能會將原來一塊很大且連續的內存區域逐漸分割成許多細小而彼此不相鄰的內存區域,產生通常說的內存碎片。當內存碎片大量存在時,最后應用程序可能連一塊很小的內存也無法分配到。(2)由于內存管理算法的原因,malloc()和free()函數的執行時間是不確定的,因此不適合作實時操作系統函數應用。
μC/OS-Ⅱ操作系統的內存管理方法是在解決了malloc()和free()兩函數缺陷的基礎上構建起來的。其原理如圖9.1所示,將內存分區分塊,也就是把連續的每個大塊內存分區,圖9.1內存分區每個分區又分成整數個大小相同的內存塊。μC/OS-Ⅱ利用這種新機制,對malloc()和free()函數進行了改進,并構建了新的內存管理函數,使得它們可以分配和釋放固定大小的內存塊。這樣一來,malloc()和free()兩函數的執行時間不確定的問題就首先得到了解決。接下來就是要解決內存碎片的問題。如圖9.1所示,在有多個分區分塊的內存系統中,分配內存時,應用程序可以從不同的內存分區中得到大小不同的內存塊。當需要釋放時,特定的內存塊再重新放回它以前所屬的內存分區。通過這樣的內存管理算法,內存碎片問題就得到了解決。9.1.2內存管理函數
如表9.1所示,μC/OS-Ⅱ提供了四種內存管理函數,函數所屬文件是OS_MEM.C。表9.1內存管理函數一覽表9.1.3內存管理函數的配置常量
在使用內存管理函數之前,必須將OS_CFG?.H文件中相應的配置常量設置為0或1,以確定是編譯還是裁剪該函數,其配置常量如表9.2所示。表9.2內存管理函數的配置常量一覽表9.1.4內存控制塊
內存控制塊(MemoryControlBlocks,MCB)是用于實現內存管理、跟蹤每一個內存分區的數據結構,如程序清單9.1所示,每個內存分區都有它自己的內存控制塊。 程序清單9.1內存控制塊的數據結構
typedefstruct{
void*OSMemAddr; /*指向內存分區起始地址的指針。它在建立內存分區時被初始化,
此后不能更改(見9.2節) */
void*OSMemFreeList;/*指向下一個空閑內存控制塊或下一個空閑內存塊的指針,具體含義
要根據該內存分區是否已經建立來決定(見9.2節) */INT32UOSMemBlkSize;/*內存分區中內存塊的大小,是用戶在建立該內存分區時指定的*/
INT32UOSMemNBlks; /*內存分區中總的內存塊數量,是用戶在建立該內存分區時指定的*/
INT32UOSMemNFree; /*內存分區中當前可以使用的空閑內存塊數量 */
}OS_MEM;如果要使用μC/OS-Ⅱ中的內存管理,首先需要將OS_CFG?.H文件中的開關量OS_MEM_EN設置為1;然后還要設置OS_MAX_MEM_PART常量,其值至少是2,它決定了系統中的最大分區數。這樣,在啟動時μC/OS-Ⅱ就會通過OSInit()調用OSMemInit()來實現對內存管理器的初始化。該初始化主要建立一個如圖9.2所示的空閑內存控制塊鏈表,其中OSMemFreeList指針的作用是將空閑內存控制塊鏈接成空閑內存控制塊鏈表。圖9.2空閑內存控制塊鏈表9.2建立內存分區——OSMemCreate()
9.2.1函數原型
函數原型如下:
OS_MEM*OSMemCreate(void*addr,INT32Unblks,INT32Ublksize,INT8U*err)
OSMemCreate()函數用于建立并初始化一塊內存區。要使用內存管理函數,必先調用OSMemCreate()函數建立內存分區。一個內存區包含確定數量和大小的內存塊,應用程序可以分配這些內存塊,并在用完后釋放回內存區。
OSMemCreate()函數有如下四個參數:(1)?addr:建立的內存區的起始地址。內存區可以使用靜態數組或在初始化時使用malloc()函數建立。
(2)?nblks:內存塊的數量。每一個內存區最少需要定義兩個內存塊。
(3)?blksize:每個內存塊的大小,最少應該能夠容納一個指針。
(4)?err:指向錯誤代碼的變量的指針。OSMemCreate()函數返回的錯誤碼可能為下述幾種之一:
①?OS_NO_ERR:內存分區建立成功。
②?OS_MEM_INVALID_ADD:地址指針為空,非法。③?OS_MEM_INVALID_PART:沒有空閑的內存區。
④?OS_MEM_INVALID_BLKS:沒有為每一個內存區建立至少兩個內存塊。
⑤?OS_MEM_INVALID_SIZE:內存塊太小,不能容納一個指針變量。
OSMemCreate()函數返回指向內存控制塊的指針。如果沒有空閑內存區,則OSMemCreate()函數返回空指針。
函數的調用者是任務或者啟動代碼,開關量是OS_MEM_EN。9.2.2源代碼
OSMemCreate()函數的源代碼如程序清單9.2所示。該函數的主要工作過程如下:
(1)條件檢查,確保各種前提條件的滿足。
(2)從空閑內存控制塊鏈表中取得一個內存控制塊。
(3)若該空閑內存控制塊可用,則將該內存分區內的所有內存塊用指針鏈接成一個單向鏈表。因為在這個鏈表中,插入和刪除元素都是從頂端開始的,所以無需使用雙向鏈表。
(4)在內存分區的控制塊中填寫與該內存分區有關的內容。
(5)最后返回該內存控制塊指針,以后的操作都通過該指針來實現。 程序清單9.2OSMemCreate()函數的源代碼
OS_MEM*OSMemCreate(void*addr,INT32Unblks,INT32Ublksize,INT8U*err)
{
#ifOS_CRITICAL_METHOD=?=3
OS_CPU_SRcpu_sr;
#endif
OS_MEM *pmem;
INT8U *pblk;
void **plink;INT32U i;
#ifOS_ARG_CHK_EN>0
if(addr =?=(void*)0){ /*確保定義的內存分區起始地址是有效的 */
*err =OS_MEM_INVALID_ADDR;
return((OS_MEM*)0);
}
if(nblks<2){ /*確保每個內存分區至少有兩個內存塊 */*err=OS_MEM_INVALID_BLKS;
return((OS_MEM*)0);
}
if(blksize<sizeof(void*)){ /*確保每個內存塊至少能容納下一條指針,因為空閑內存控制塊是由指針鏈接在一起的 */
*err=OS_MEM_INVALID_SIZE;
return((OS_MEM*)0);
}#endif
OS_ENTER_CRITICAL();
pmem=OSMemFreeList; /*從空閑內存控制塊鏈表中取得一個空閑內存控制塊 */
if(OSMemFreeList !=(OS_MEM*)0){ /*確保取得的空閑內存控制塊是可用的 */
OSMemFreeList =(OS_MEM*)OSMemFreeList->OSMemFreeList; /*調整指針 */
}
OS_EXIT_CRITICAL();if(pmem==(OS_MEM*)0){ /*檢查內存控制塊是否可用 */
*err=OS_MEM_INVALID_PART;
return((OS_MEM*)0);
}
/*滿足上述條件后,將所要建立的內存分區內的所有內存塊鏈接成一個單向鏈表 */
plink=(void**)addr; /*建立單向鏈表 */
pblk=(INT8U*)addr+blksize;
for(i=0;i<(nblks-1);i++){*plink =(void*)pblk;
plink =*plink;
pblk =pblk+blksize;
}
/*在該內存分區控制塊中填寫與內存分區有關的信息 */
*plink =(void*)0;/*最后一條指針指向NULL */
/*在該內存分區控制塊中填寫與內存分區有關的信息 */pmem->OSMemAddr =addr; /*存儲內存分區的起始地址 */
pmem->OSMemFreeList =addr; /*初始化空閑內存塊指針 */
pmem->OSMemNFree =nblks; /*存儲內存塊的數量 */
pmem->OSMemNBlks =nblks;
pmem->OSMemBlkSize =blksize; /*存儲每個內存塊的尺寸 */
*err =OS_NO_ERR;
return(pmem);/*返回內存控制塊指針,以后對該內存分區的操作都通過這個指針來實現*/
}
OSMemCretae()函數運行完畢后,內存控制塊所指向的內存分區與分區中的內存塊之間的關系如圖9.3所示。圖9.3OSMemCretae()函數建立的內存分區程序一旦運行,經過多次分配與釋放內存塊后,同一分區內的內存塊的鏈接順序會有很大變化,但這并不影響使用,也不增加時間開銷。
9.2.3范例
建立一個含有50個內存塊、每個內存塊為16B的內存分區,具體代碼如下:OS_MEM*MemBuf; /*定義一個內存控制塊指針 */
INT8Ubuffer[50][16]; /*定義一個內存分區數組 */
voidmain(void){
INT8Uerr;
OSInit();
.
MemBuf=OSMemCreate(buffer,50,16,&err);
.
OSStart();
} 9.3分配內存塊——OSMemGet()
9.3.1函數原型
函數原型如下:
void*OSMemGet(OS_MEM*pmem,INT8U*err)
OSMemGet()函數用于從已經建立的內存分區中申請一個內存塊。該函數的調用者可以是任務或者中斷,開關量是OS_MEM_EN。該函數有如下兩個參數:(1)?pmem:指向內存控制塊的指針。其值可以在建立內存分區時得到。
(2)?err:指向包含錯誤碼的變量的指針。返回的錯誤碼可能為下述幾種之一:
①?OS_NO_ERR:成功得到一個內存塊。
②?OS_MEM_NO_FREE_BLKS:內存區中已經沒有空閑內存塊。
③?OS_MEM_INVALID_PMEM:pmem是空指針。
函數返回指向內存區塊的指針,如果沒有空間分配給內存塊,函數返回空指針。9.3.2注意事項
調用OSMemGet()函數時應注意如下事項:
(1)調用該函數申請內存塊時,用戶必須知道所建立的內存塊的大小,使用時不能超過容量。例如,如果一個內存分區內的每個內存塊為64B,那么應用程序最多只能使用該內存塊中的64B。
(2)用戶程序必須在使用完內存塊后及時釋放,并重新放回它原先屬于的分區中去。
(3)函數可以多次調用。
(4)如果暫時沒有內存塊可用,函數不會等待,而是立即返回NULL指針,所以可在中斷中調用。9.3.3源代碼
OSMemGet()函數的源代碼如程序清單9.3所示。該函數的主要工作過程如下:
(1)確保運行條件的滿足。
(2)檢查分區是否有空閑的內存塊,若有,則取得它,并作如下操作:因為已經從空閑內存塊中取走了,所以要將它從空閑內存塊鏈表中刪除,并調整空閑內存塊的指針,空閑內存塊的數量也要相應減1;若沒有空閑的內存塊,則返回錯誤代碼。 程序清單9.3OSMemGet()函數的源代碼
void*OSMemGet(OS_MEM*pmem,INT8U*err)
{
#ifOS_CRITICAL_METHOD=?=3
OS_CPU_SRcpu_sr;
#endif
void*pblk;
#ifOS_ARG_CHK_EN>0
if(pmem=?=(OS_MEM*)0){ /*確保指針指向的內存控制塊是有效的 */*err=OS_MEM_INVALID_PMEM;
return((OS_MEM*)0);
}
#endif
OS_ENTER_CRITICAL();
if(pmem->OSMemNFree>0){ /*檢查分區中是否有空閑的內存塊 */
pblk=pmem->OSMemFreeList; /*如果有,則將第一個內存塊從空閑內存塊鏈表中刪除,因為此時要使用這個內存控制塊*/pmem->OSMemFreeList=*(void**)pblk; /*調整空閑內存塊鏈表指針 */
pmem->OSMemNFree--; /*空閑內存塊數量減1 */
OS_EXIT_CRITICAL();
*err=OS_NO_ERR; /*申請成功 */
return(pblk); /*將分配到的內存塊指針返回給應用程序 */}
OS_EXIT_CRITICAL();
*err=OS_MEM_NO_FREE_BLKS; /*如果沒有空閑內存塊,返回錯誤代碼 */
return((void*)0); /*返回空指針 */
}
9.3.4范例
OSMemGet()函數的使用范例如下:OS_MEM*MemBuf; /*定義一個內存控制塊指針 */
voidTask(void*pdata){
INT8U*msg;pdata=pdata;
for(;;){
msg=OSMemGet(MemBuf,&err);
if(msg!=(INT8U*)0){
./*內存塊已經分配 */
}
}
} 9.4釋放內存塊——OSMemPut()
9.4.1函數原型
函數原型如下:
INT8UOSMemPut(OS_MEM*pmem,void*pblk)
OSMemPut()函數用于釋放一個內存塊。開關量是OS_MEM_EN,調用者是任務或者中斷。該函數有如下兩個參數:
(1)?pmem:指向內存控制塊的指針。其值可以在調用OSMemCreate()函數建立內存分區的時候得到。
(2)?pblk:指向將要被釋放的內存塊的指針。9.4.2返回值
OSMemPut()函數的返回值為下述內容之一:
(1)?OS_NO_ERR:內存塊成功釋放。
(2)?OS_MEM_FULL:內存分區已滿,不能再接收釋放的內存塊。這種情況說明用戶程序出現了錯誤,釋放的內存塊多于用OSMemGet()函數得到的內存塊。
(3)?OS_MEM_INVALID_PMEM:pmem是空指針。
(4)?OS_MEM_INVALID_PBLK:pblk是空指針。9.4.3注意事項
調用OSMemPut()函數時應注意如下事項:
(1)如果一個內存塊已經不再使用,必須及時釋放它,以備其它應用程序使用。
(2)釋放內存塊時,必須放回到原先申請的內存分區中,不能錯放,否則可能導致系統崩潰。例如,從每個內存塊是32B的內存分區中申請了一個內存塊,用完后就不能把它返回給每個內存塊是64B的內存分區。因為,應用程序以后申請64B分區中的內存塊時,可能會只得到32B的可用空間,而得不到64B的內存塊。9.4.4源代碼
OSMemPut()函數的源代碼如程序清單9.4所示。該函數的主要工作過程如下:首先檢查內存分區是否已滿,如果已滿,則說明系統在分配和釋放內存時出現了錯誤;如果未滿,則將所要釋放的內存塊插入到該分區的空閑內存塊鏈表中。最后,將分區中空閑內存塊總數加1。 程序清單9.4OSMemPut()函數的源代碼
INT8UOSMemPut(OS_MEM*pmem,void*pblk)
{
#ifOS_CRITICAL_METHOD=?=3
OS_CPU_SRcpu_sr;
#endif
#ifOS_ARG_CHK_EN>0
if(pmem=?=(OS_MEM*)0){ /*確保指針指向的內存控制塊是有效的*/return(OS_MEM_INVALID_PMEM);
}
if(pblk=?=(void*)0){ /*確保釋放的內存塊是有效的 */
return(OS_MEM_INVALID_PBLK);
}
#endif
OS_ENTER_CRITICAL();
if(pmem->OSMemNFree>=pmem->OSMemNBlks){ /*檢查內存分區是否已滿 */OS_EXIT_CRITICAL(); /*若滿,則說明分配或者釋放內存時出現了錯誤 */
return(OS_MEM_FULL);
}
/*內存分區未滿 */
*(void**)pblk=pmem->OSMemFreeList;/*將需要釋放的內存塊返回給空閑內存控制塊鏈表*/pmem->OSMemFreeList=pblk; /*調整指針,將所釋放的內存塊放在鏈表的最前面 */
pmem->OSMemNFree++; /*將分區中的空閑內存塊總數加1 */
OS_EXIT_CRITICAL();
return(OS_NO_ERR); /*通知調用者釋放成功 */
}
9.4.5范例
OSMemPut()函數的使用范例如下:OS_MEM*MemBuf; /*定義一個內存控制塊指針 */
INT8U*MemMsg; /*定義一個內存塊指針 */
voidTask(void*pdata){
INT8Uerr;
pdata=pdata;
for(;;){
err=OSMemPut(MemBuf,(void*)MemMsg);if(err=?=OS_NO_ERR){
. /*處理代碼 */
}
.
}
}9.5查詢內存分區的狀態——OSMemQuery()
9.5.1函數原型
函數原型如下:
INT8UOSMemQuery(OS_MEM*pmem,OS_MEM_DATA*pdata)
OSMemQuery()函數可以查詢特定內存分區中的有關信息。該函數使用了一個新的OS_MEM_DATA的數據結構來復制OS_MEM結構中的信息,并比OS_MEM多一個成員。OS_MEM_DATA的數據結構如程序清單9.5所示。函數的調用者可以是任務或者中斷,開關量是OS_MEM_EN和OS_MEM_QUERY_EN。該函數有如下兩個參數:(1)?pmem:指向內存控制塊的指針。其值可以在調用OSMemCreate()函數時返回得到。
(2)?pdata:指向OS_MEM_DATA數據結構的指針。它比OS_MEM多一個成員。 程序清單9.5OS_MEM_DATA的數據結構
typedefstruct{
void OSAddr; /*指向內存分區起始地址的指針 */
void OSFreeList; /*指向空閑內存塊列表起始地址的指針 */
INT32U OSBlkSize; /*每個內存塊的大小 */ INT32U OSNBlks; /*內存分區的內存塊總數 */
INT32U OSNFree; /*空閑的內存塊數量 */
INT32U OSNUsed; /*正在使用的內存塊數量 */
}OS_MEM_DATA;9.5.2返回值
OSMemQuery()函數的返回值為下述內容之一:
(1)?OS_NO_ERR:調用成功。
(2)?OS_MEM_INVALID_PMEM:pmem是空指針。
(3)?OS_MEM_INVALID_PDATA:pdata是空指針。
9.5.3源代碼
OSMemQuery()函數的源代碼如程序清單9.6所示,它將指定內存分區的信息復制到OS_MEM_DATA定義的變量中。 程序清單9.6OSMemQuery()函數的源代碼
#ifOS_MEM_QUERY_EN>0
INT8UOSMemQuery(OS_MEM*pmem,OS_MEM_DATA*ppdata)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 醫療行業的人才需求與數字化招聘對策
- 醫療軟件本地化設計策略分析
- VB編程答案方法試題及答案
- 小米校招筆試題目及答案
- 2025年軟件設計師創新試題及答案
- 進一步理解VB考試試題及答案
- 2025年軟考網絡管理員應知應會題目及答案
- 數據安全與隱私保護考試題目及答案
- 應用推廣軟件設計師考試試題及答案
- 大數據在智慧教育中的應用研究
- 《閩南高甲戲民俗文化旅游開發中存在的問題及優化策略》5100字(論文)
- 客戶溝通與服務技巧考核試卷
- 機場安檢液態物品培訓
- 計算機的基本工作原理初中七年級上冊信息技術課件
- 腸瘺 課件教學課件
- 加油站防雷制度檔案
- 2024年四川省巴中市中考文科綜合試卷(含答案解析)
- 欠款抵車的協議書范本
- 設備購買合同模板示例
- 基于JAVA的寵物管理系統實現畢業論文
- 2024年小區地下車位租賃合同
評論
0/150
提交評論