從FreeRTOS V9.0.0開始內(nèi)核對象既可以在編譯的時候靜態(tài)分配帖汞,也可以在運行時動態(tài)分配左权。為了盡可能讓FreeRTOS易于使用嘉赎,這些內(nèi)核對象并不是在編譯時靜態(tài)分配的膝晾,而是在運行時動態(tài)分配的米辐。內(nèi)核對象創(chuàng)建時FreeRTOS分配RAM而在內(nèi)核對象刪除時釋放內(nèi)存胸完。這樣簡化了API,并且減少了RAM的占用翘贮。
動態(tài)內(nèi)存分配是C語言編程的概念赊窥,而不是針對FreeRTOS或者多任務(wù)編程的概念。它和FreeRTOS是相關(guān)的狸页,因為內(nèi)核對象是動態(tài)分配的锨能,并且通用編譯器提供的動態(tài)內(nèi)存分配方案對于實時應(yīng)用程序并不總是適合的。
內(nèi)存可以使用標(biāo)準(zhǔn)C庫的malloc()和free()函數(shù)來分配芍耘,但直接調(diào)用這兩個函數(shù)可能不適合腹侣,原因有以下幾點:
1. malloc()和free()函數(shù)在小型嵌入式系統(tǒng)中并不總是可用的
2. 它們的實現(xiàn)可能非常的大,占據(jù)了相當(dāng)大的一塊代碼空間
3. 他們幾乎都不是線程安全的
4. 它們并不是確定的齿穗,每次調(diào)用這些函數(shù)執(zhí)行的時間可能都不一樣
5. 它們有可能產(chǎn)生碎片
6. 它們有可能打亂鏈接器的配置
7. 如果允許堆空間的生長方向覆蓋其他變量占據(jù)的內(nèi)存傲隶,它們會成為debug的災(zāi)難
動態(tài)內(nèi)存分配的可選
從FreeRTOS V9.0.0開始內(nèi)核對象既可以在編譯時靜態(tài)分配也可以在運行時動態(tài)分配。如今FreeRTOS把內(nèi)存分配放在可移植層窃页。這是考慮到不同的嵌入式系統(tǒng)有不同的動態(tài)內(nèi)存管理方法和時間要求跺株,因此單個的動態(tài)內(nèi)存分配算法將只適合于應(yīng)用程序的一個子集复濒。同樣,如果有需要的話乒省,開發(fā)人員可以從核心代碼庫中移除動態(tài)內(nèi)存分配巧颈。
當(dāng)FreeRTOS需要RAM的時候,并不是調(diào)用malloc()袖扛,而是調(diào)用pvPortMalloc()砸泛。當(dāng)需要釋放RAM的時候,并不是調(diào)用free()蛆封,而是調(diào)用vPortFree()唇礁。pvPortMalloc()和標(biāo)準(zhǔn)C庫的malloc()有同樣的函數(shù)原型,vPortFree()和標(biāo)準(zhǔn)C庫的free()有同樣的函數(shù)原型惨篱。
pvPortMalloc()和vPortFree()都是公共函數(shù)盏筐,因此能夠被應(yīng)用代碼調(diào)用。
FreeRTOS對于pvPortMalloc()和vPortFree()提供了5種實現(xiàn)砸讳。FreeRTOS應(yīng)用程序可以使用其中的一種琢融,或者使用自己的實現(xiàn)。
5種實現(xiàn)分別在heap_1.c,heap_2.c,heap_3.c,heap_4.c和heap_5.c文件中簿寂,都存在于文件夾FreeRTOS/Source/portable/MemMang下漾抬。
下面來介紹一下其中的一種實現(xiàn) Heap_1:
小型嵌入式系統(tǒng)通常只在啟動調(diào)度程序之前創(chuàng)建任務(wù)和其他內(nèi)核對象。在這種情況下常遂,內(nèi)存只能在應(yīng)用程序開始執(zhí)行任何實時功能之前由內(nèi)核動態(tài)分配纳令,并且內(nèi)存將在應(yīng)用程序的生命周期內(nèi)保持不被釋放。這意味著所選擇的分配方案不需要考慮任何更復(fù)雜的內(nèi)存分配問題烈钞,比如確定性和碎片化泊碑,而只需要考慮代碼大小和簡單性等屬性坤按。
Heap_1.c實現(xiàn)了一個非程盒溃基本的pvPortMalloc()版本,但沒有實現(xiàn)vPortFree()臭脓。heap_1適用于從不刪除任務(wù)或其他內(nèi)核對象的應(yīng)用程序酗钞。
一些禁止使用動態(tài)內(nèi)存分配的關(guān)鍵的商業(yè)系統(tǒng)和關(guān)鍵的安全系統(tǒng)也有可能使用heap_1。由于擔(dān)心出現(xiàn)不確定性来累、內(nèi)存碎片化和內(nèi)存分配失敗等問題砚作,關(guān)鍵系統(tǒng)通常禁止動態(tài)內(nèi)存分配,但是Heap_1總是確定性的嘹锁,并且不能分割內(nèi)存葫录。
當(dāng)調(diào)用pvPortMalloc()時,heap_1分配方案將簡單數(shù)組細(xì)分為更小的塊领猾。這個數(shù)組稱為FreeRTOS堆米同。
數(shù)組的大小(以字節(jié)為單位)由FreeRTOSConfig.h中的configTOTAL_HEAP_SIZE定義設(shè)置骇扇。以這種方式定義一個大數(shù)組會使應(yīng)用程序看起來消耗大量ram——甚至在從數(shù)組中分配任何內(nèi)存之前也是如此。
每個創(chuàng)建的任務(wù)都需要一個任務(wù)控制塊(TCB)和一個從堆中分配的堆棧面粮。圖5演示了heap_1如何在創(chuàng)建任務(wù)時細(xì)分簡單數(shù)組少孝。
如上圖所示:
A. 在創(chuàng)建任何任務(wù)之前顯示數(shù)組——整個數(shù)組是空閑的。
B. 顯示創(chuàng)建一個任務(wù)后的數(shù)組熬苍。
C. 顯示創(chuàng)建了三個任務(wù)之后的數(shù)組稍走。