FreeRTOS實(shí)時(shí)操作系統(tǒng)的內(nèi)存管理分析
前言
本文介紹內(nèi)存管理的基礎(chǔ)知識(shí),詳細(xì)源碼分析見(jiàn)《 FreeRTOS內(nèi)存管理示例分析》
FreeRTOS提供了幾個(gè)內(nèi)存堆管理方案,有復(fù)雜的也有簡(jiǎn)單的。其中最簡(jiǎn)單的管理策略也能滿足很多應(yīng)用的要求,比如對(duì)安全要求高的應(yīng)用,這些應(yīng)用根本不允許動(dòng)態(tài)內(nèi)存分配的。
FreeRTOS也允許你自己實(shí)現(xiàn)內(nèi)存堆管理,甚至允許你同時(shí)使用兩種內(nèi)存堆管理方案。同時(shí)實(shí)現(xiàn)兩種內(nèi)存堆允許任務(wù)堆棧和其它RTOS對(duì)象放置到快速的內(nèi)部RAM,應(yīng)用數(shù)據(jù)放置到低速的外部RAM。
每當(dāng)創(chuàng)建任務(wù)、隊(duì)列、互斥量、軟件定時(shí)器、信號(hào)量或事件組時(shí),RTOS內(nèi)核會(huì)為它們分配RAM。標(biāo)準(zhǔn)函數(shù)庫(kù)中的malloc()和free()函數(shù)有些時(shí)候能夠用于完成這個(gè)任務(wù),但是:
- 在嵌入式系統(tǒng)中,它們并不總是可以使用的;
- 它們會(huì)占用更多寶貴的代碼空間;
- 它們沒(méi)有線程保護(hù);
- 它們不具有確定性(每次調(diào)用執(zhí)行的時(shí)間可能會(huì)不同);
因此,提供一個(gè)替代的內(nèi)存分配方案通常是必要的。
嵌入式/實(shí)時(shí)系統(tǒng)具有千差萬(wàn)別的RAM和時(shí)間要求,因此一個(gè)RAM內(nèi)存分配算法可能僅屬于一個(gè)應(yīng)用的子集。
為了避免這個(gè)問(wèn)題,F(xiàn)reeRTOS在移植層保留內(nèi)存分配API函數(shù)。移植層在RTOS核心代碼源文件之外(不屬于核心源代碼),這使得不同的應(yīng)用程序可以提供適合自己的應(yīng)用實(shí)現(xiàn)。當(dāng)RTOS內(nèi)核需要RAM時(shí),調(diào)用pvPortMallo()函數(shù)來(lái)代替malloc()函數(shù)。當(dāng)RAM要被釋放時(shí),調(diào)用vPortFree()函數(shù)來(lái)代替free()函數(shù)。
FreeRTOS下載包中提供5種簡(jiǎn)單的內(nèi)存分配實(shí)現(xiàn),本文稍后會(huì)進(jìn)行描述。用戶可以適當(dāng)?shù)倪x擇其中的一個(gè),也可以自己設(shè)計(jì)內(nèi)存分配策略。
FreeRTOS提供的內(nèi)存分配方案分別位于不同的源文件(heap_1.c、heap_2.c、heap_3.c、heap_4.c、heap_5.c)之中,源文件位于下載包\FreeRTOS\Source\portable\MemMang文件夾中。其它實(shí)現(xiàn)方法可以根據(jù)需要增加。如果要使用FreeRTOS提供的內(nèi)存堆分配方案,選中的源文件必須被正確的包含到工程文件中。
1.heap_1.c
這是所有實(shí)現(xiàn)中最簡(jiǎn)單的一個(gè)。一旦分配內(nèi)存之后,它甚至不允許釋放分配的內(nèi)存。盡管這樣,heap_1.c還是適用于大部分嵌入式應(yīng)用程序。這是因?yàn)榇蠖鄶?shù)深度嵌入式(deeplyembedded)應(yīng)用只是在系統(tǒng)啟動(dòng)時(shí)創(chuàng)建所有任務(wù)、隊(duì)列、信號(hào)量等,并且直到程序結(jié)束都會(huì)一直使用它們,永遠(yuǎn)不需要?jiǎng)h除。
當(dāng)需要分配RAM時(shí),這個(gè)內(nèi)存分配方案只是簡(jiǎn)單的將一個(gè)大數(shù)組細(xì)分出一個(gè)子集來(lái)。大數(shù)組的容量大小通過(guò)FreeRTOSConfig.h文件中的configTOTAL_HEAP_SIZE宏來(lái)設(shè)置。
API函數(shù)xPortGetFreeHeapSize()返回未分配的堆??臻g總大小,可以通過(guò)這個(gè)函數(shù)返回值對(duì)configTOTAL_HEAP_SIZE進(jìn)行合理的設(shè)置。
功能簡(jiǎn)介:
- 用于從不會(huì)刪除任務(wù)、隊(duì)列、信號(hào)量、互斥量等的應(yīng)用程序(實(shí)際上大多數(shù)使用FreeRTOS的應(yīng)用程序都符合這個(gè)條件)
- 執(zhí)行時(shí)間是確定的并且不會(huì)產(chǎn)生內(nèi)存碎片
- 實(shí)現(xiàn)和分配過(guò)程非常簡(jiǎn)單,需要的內(nèi)存是從一個(gè)靜態(tài)數(shù)組中分配的,意味著這種內(nèi)存分配通常只是適用于那些不進(jìn)行動(dòng)態(tài)內(nèi)存分配的應(yīng)用。
2.heap_2.c
和方案1不同,這個(gè)方案使用一個(gè)最佳匹配算法,它允許釋放之前分配的內(nèi)存塊。它不會(huì)把相鄰的空閑塊合成一個(gè)更大的塊(換句話說(shuō),這會(huì)造成內(nèi)存碎片)。
有效的堆??臻g大小由位于FreeRTOSConfig.h文件中的configTOTAL_HEAP_SIZE宏來(lái)定義。
API函數(shù)xPortGetFreeHeapSize()返回剩下的未分配堆??臻g的大小(可用于優(yōu)化設(shè)置configTOTAL_HEAP_SIZE宏的值),但是不能提供未分配內(nèi)存的碎片細(xì)節(jié)信息。
功能簡(jiǎn)介:
可以用于重復(fù)的分配和刪除具有相同堆??臻g的任務(wù)、隊(duì)列、信號(hào)量、互斥量等等,并且不考慮內(nèi)存碎片的應(yīng)用程序。
不能用在分配和釋放隨機(jī)字節(jié)堆??臻g的應(yīng)用程序
- 如果一個(gè)應(yīng)用程序動(dòng)態(tài)的創(chuàng)建和刪除任務(wù),并且分配給任務(wù)的堆??臻g總是同樣大小,那么大多數(shù)情況下heap_2.c是可以使用的。但是,如果分配給任務(wù)的堆棧不總是相等,那么釋放的有效內(nèi)存可能碎片化,形成很多小的內(nèi)存塊。最后會(huì)因?yàn)闆](méi)有足夠大的連續(xù)堆??臻g而造成內(nèi)存分配失敗。在這種情況下,heap_4.c是一個(gè)很好的選擇。
- 如果一個(gè)應(yīng)用程序動(dòng)態(tài)的創(chuàng)建和刪除隊(duì)列,并且在每種情況下隊(duì)列存儲(chǔ)區(qū)域(隊(duì)列存儲(chǔ)區(qū)域指隊(duì)列項(xiàng)數(shù)目乘以每個(gè)隊(duì)列長(zhǎng)度)都是同樣的,那么大多數(shù)情況下heap_2.c可以使用。但是,如果隊(duì)列存儲(chǔ)區(qū)在每種情況下并不總是相等,那么釋放的有效內(nèi)存可能碎片化,形成很多小的內(nèi)存塊。最后會(huì)因?yàn)闆](méi)有足夠大的連續(xù)堆棧空間而造成內(nèi)存分配失敗。在這種情況下,heap_4.c是一個(gè)很好的選擇。
- 應(yīng)用程序直接調(diào)用pvPortMalloc() 和 vPortFree()函數(shù),而不僅是通過(guò)FreeRTOS API間接調(diào)用。
如果你的應(yīng)用程序中的隊(duì)列、任務(wù)、信號(hào)量、互斥量等等處在一個(gè)不可預(yù)料的順序,則可能會(huì)導(dǎo)致內(nèi)存碎片問(wèn)題,雖然這是小概率事件,但必須牢記。
不具有確定性,但是它比標(biāo)準(zhǔn)庫(kù)中的malloc函數(shù)具有高得多的效率。
heap_2.c適用于需要?jiǎng)討B(tài)創(chuàng)建任務(wù)的大多數(shù)小型實(shí)時(shí)系統(tǒng)(smallreal time)。
3.heap_3.c
heap_3.c簡(jiǎn)單的包裝了標(biāo)準(zhǔn)庫(kù)中的malloc()和free()函數(shù),包裝后的malloc()和free()函數(shù)具備線程保護(hù)。
功能簡(jiǎn)介:
- 需要鏈接器設(shè)置一個(gè)堆棧,并且編譯器庫(kù)提供malloc()和free()函數(shù)。
- 不具有確定性
- 可能明顯的增大RTOS內(nèi)核的代碼大小
注:使用heap_3時(shí),F(xiàn)reeRTOSConfig.h文件中的configTOTAL_HEAP_SIZE宏定義沒(méi)有作用。
4.heap_4.c
這個(gè)方案使用一個(gè)最佳匹配算法,但不像方案2那樣。它會(huì)將相鄰的空閑內(nèi)存塊合并成一個(gè)更大的塊(包含一個(gè)合并算法)。
有效的堆??臻g大小由位于FreeRTOSConfig.h文件中的configTOTAL_HEAP_SIZE來(lái)定義。
API函數(shù)xPortGetFreeHeapSize()返回剩下的未分配堆??臻g的大?。捎糜趦?yōu)化設(shè)置configTOTAL_HEAP_SIZE宏的值),但是不能提供未分配內(nèi)存的碎片細(xì)節(jié)信息。
功能簡(jiǎn)介:
- 可用于重復(fù)分配、刪除任務(wù)、隊(duì)列、信號(hào)量、互斥量等等的應(yīng)用程序。
- 可以用于分配和釋放隨機(jī)字節(jié)內(nèi)存的情況,并不像heap_2.c那樣產(chǎn)生嚴(yán)重碎片。
- 不具有確定性,但是它比標(biāo)準(zhǔn)庫(kù)中的malloc函數(shù)具有高得多的效率。
heap_4.c還特別適用于移植層代碼,可以直接使用pvPortMalloc()和 vPortFree()函數(shù)來(lái)分配和釋放內(nèi)存。
5.heap_5.c(V8.1.0新增)
這個(gè)方案同樣實(shí)現(xiàn)了heap_4.c中的合并算法,并且允許堆棧跨越多個(gè)非連續(xù)的內(nèi)存區(qū)。
Heap_5通過(guò)調(diào)用vPortDefineHeapRegions()函數(shù)實(shí)現(xiàn)初始化,在該函數(shù)執(zhí)行完成前不允許使用內(nèi)存分配和釋放。創(chuàng)建RTOS對(duì)象(任務(wù)、隊(duì)列、信號(hào)量等等)會(huì)隱含的調(diào)用pvPortMalloc(),因此必須注意:使用heap_5創(chuàng)建任何對(duì)象前,要先執(zhí)行vPortDefineHeapRegions()函數(shù)。
vPortDefineHeapRegions()函數(shù)只需要單個(gè)參數(shù)。該參數(shù)是一個(gè)HeapRegion_t結(jié)構(gòu)體類(lèi)型數(shù)組。HeapRegion_t在portable.h中定義,如下所示:
typedef struct HeapRegion { /* 用于內(nèi)存堆的內(nèi)存塊起始地址*/ uint8_t *pucStartAddress; /* 內(nèi)存塊大小 */ size_t xSizeInBytes; } HeapRegion_t;
這個(gè)數(shù)組必須使用一個(gè)NULL指針和0字節(jié)元素作為結(jié)束,起始地址必須從小到大排列。下面的代碼段提供一個(gè)例子。MSVCWin32模擬器演示例程使用了heap_5,因此可以當(dāng)做一個(gè)參考例程。
/* 在內(nèi)存中為內(nèi)存堆分配兩個(gè)內(nèi)存塊.第一個(gè)內(nèi)存塊0x10000字節(jié),起始地址為0x80000000, 第二個(gè)內(nèi)存塊0xa0000字節(jié),起始地址為0x90000000.起始地址為0x80000000的內(nèi)存塊的 起始地址更低,因此放到了數(shù)組的第一個(gè)位置.*/ const HeapRegion_t xHeapRegions[] = { { ( uint8_t * ) 0x80000000UL, 0x10000 }, { ( uint8_t * ) 0x90000000UL, 0xa0000 }, { NULL, 0 } /* 數(shù)組結(jié)尾. */ }; /* 向函數(shù)vPortDefineHeapRegions()傳遞數(shù)組參數(shù). */ vPortDefineHeapRegions( xHeapRegions );
以上就是FreeRTOS實(shí)時(shí)操作系統(tǒng)的內(nèi)存管理分析的詳細(xì)內(nèi)容,更多關(guān)于FreeRTOS內(nèi)存管理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- FreeRTOS動(dòng)態(tài)內(nèi)存分配管理heap_2示例
- FreeRTOS動(dòng)態(tài)內(nèi)存分配管理heap_1示例
- FreeRTOS實(shí)時(shí)操作系統(tǒng)空閑任務(wù)的阻塞延時(shí)實(shí)現(xiàn)
- FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)創(chuàng)建與任務(wù)切換
- FreeRTOS實(shí)時(shí)操作系統(tǒng)的列表與列表項(xiàng)操作示例
- FreeRTOS實(shí)時(shí)操作系統(tǒng)的多優(yōu)先級(jí)實(shí)現(xiàn)
- FreeRTOS實(shí)時(shí)操作系統(tǒng)支持時(shí)間片示例詳解
- FreeRTOS動(dòng)態(tài)內(nèi)存分配管理heap_4示例
相關(guān)文章
FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)創(chuàng)建和刪除
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)創(chuàng)建和刪除,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)創(chuàng)建與任務(wù)切換
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)創(chuàng)建與任務(wù)切換,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS進(jìn)階之任務(wù)創(chuàng)建完全解析
這篇文章主要為大家介紹了FreeRTOS進(jìn)階之任務(wù)創(chuàng)建完全解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)Cortex-M內(nèi)核使用注意事項(xiàng)
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)Cortex-M內(nèi)核使用注意事項(xiàng),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS進(jìn)階之調(diào)度器啟動(dòng)過(guò)程分析
這篇文章主要為大家介紹了FreeRTOS進(jìn)階之調(diào)度器啟動(dòng)過(guò)程分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)內(nèi)核配置說(shuō)明
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)內(nèi)核配置及說(shuō)明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS進(jìn)階之任務(wù)通知示例完全解析
這篇文章主要為大家介紹了FreeRTOS進(jìn)階系列之任務(wù)通知的示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)之可視化追蹤調(diào)試
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)之可視化追蹤調(diào)試的示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS軟件定時(shí)器apollo中斷狀態(tài)判斷
這篇文章主要為大家介紹了FreeRTOS軟件定時(shí)器apollo中斷狀態(tài)的判斷,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04