網(wǎng)站首頁 編程語言 正文
前言
本文介紹內(nèi)存管理的基礎知識,詳細源碼分析見《?FreeRTOS內(nèi)存管理示例分析》
FreeRTOS提供了幾個內(nèi)存堆管理方案,有復雜的也有簡單的。其中最簡單的管理策略也能滿足很多應用的要求,比如對安全要求高的應用,這些應用根本不允許動態(tài)內(nèi)存分配的。
FreeRTOS也允許你自己實現(xiàn)內(nèi)存堆管理,甚至允許你同時使用兩種內(nèi)存堆管理方案。同時實現(xiàn)兩種內(nèi)存堆允許任務堆棧和其它RTOS對象放置到快速的內(nèi)部RAM,應用數(shù)據(jù)放置到低速的外部RAM。
每當創(chuàng)建任務、隊列、互斥量、軟件定時器、信號量或事件組時,RTOS內(nèi)核會為它們分配RAM。標準函數(shù)庫中的malloc()和free()函數(shù)有些時候能夠用于完成這個任務,但是:
- 在嵌入式系統(tǒng)中,它們并不總是可以使用的;
- 它們會占用更多寶貴的代碼空間;
- 它們沒有線程保護;
- 它們不具有確定性(每次調(diào)用執(zhí)行的時間可能會不同);
? ? ? 因此,提供一個替代的內(nèi)存分配方案通常是必要的。
? ? ? 嵌入式/實時系統(tǒng)具有千差萬別的RAM和時間要求,因此一個RAM內(nèi)存分配算法可能僅屬于一個應用的子集。
? ? ? 為了避免這個問題,F(xiàn)reeRTOS在移植層保留內(nèi)存分配API函數(shù)。移植層在RTOS核心代碼源文件之外(不屬于核心源代碼),這使得不同的應用程序可以提供適合自己的應用實現(xiàn)。當RTOS內(nèi)核需要RAM時,調(diào)用pvPortMallo()函數(shù)來代替malloc()函數(shù)。當RAM要被釋放時,調(diào)用vPortFree()函數(shù)來代替free()函數(shù)。
? ? ? FreeRTOS下載包中提供5種簡單的內(nèi)存分配實現(xiàn),本文稍后會進行描述。用戶可以適當?shù)倪x擇其中的一個,也可以自己設計內(nèi)存分配策略。
? ? ? FreeRTOS提供的內(nèi)存分配方案分別位于不同的源文件(heap_1.c、heap_2.c、heap_3.c、heap_4.c、heap_5.c)之中,源文件位于下載包\FreeRTOS\Source\portable\MemMang文件夾中。其它實現(xiàn)方法可以根據(jù)需要增加。如果要使用FreeRTOS提供的內(nèi)存堆分配方案,選中的源文件必須被正確的包含到工程文件中。
1.heap_1.c
這是所有實現(xiàn)中最簡單的一個。一旦分配內(nèi)存之后,它甚至不允許釋放分配的內(nèi)存。盡管這樣,heap_1.c還是適用于大部分嵌入式應用程序。這是因為大多數(shù)深度嵌入式(deeplyembedded)應用只是在系統(tǒng)啟動時創(chuàng)建所有任務、隊列、信號量等,并且直到程序結束都會一直使用它們,永遠不需要刪除。
當需要分配RAM時,這個內(nèi)存分配方案只是簡單的將一個大數(shù)組細分出一個子集來。大數(shù)組的容量大小通過FreeRTOSConfig.h文件中的configTOTAL_HEAP_SIZE宏來設置。
API函數(shù)xPortGetFreeHeapSize()返回未分配的堆棧空間總大小,可以通過這個函數(shù)返回值對configTOTAL_HEAP_SIZE進行合理的設置。
功能簡介:
- 用于從不會刪除任務、隊列、信號量、互斥量等的應用程序(實際上大多數(shù)使用FreeRTOS的應用程序都符合這個條件)
- 執(zhí)行時間是確定的并且不會產(chǎn)生內(nèi)存碎片
- 實現(xiàn)和分配過程非常簡單,需要的內(nèi)存是從一個靜態(tài)數(shù)組中分配的,意味著這種內(nèi)存分配通常只是適用于那些不進行動態(tài)內(nèi)存分配的應用。
2.heap_2.c
和方案1不同,這個方案使用一個最佳匹配算法,它允許釋放之前分配的內(nèi)存塊。它不會把相鄰的空閑塊合成一個更大的塊(換句話說,這會造成內(nèi)存碎片)。
有效的堆??臻g大小由位于FreeRTOSConfig.h文件中的configTOTAL_HEAP_SIZE宏來定義。
?API函數(shù)xPortGetFreeHeapSize()返回剩下的未分配堆棧空間的大?。捎糜趦?yōu)化設置configTOTAL_HEAP_SIZE宏的值),但是不能提供未分配內(nèi)存的碎片細節(jié)信息。
功能簡介:
可以用于重復的分配和刪除具有相同堆棧空間的任務、隊列、信號量、互斥量等等,并且不考慮內(nèi)存碎片的應用程序。
不能用在分配和釋放隨機字節(jié)堆??臻g的應用程序
- 如果一個應用程序動態(tài)的創(chuàng)建和刪除任務,并且分配給任務的堆??臻g總是同樣大小,那么大多數(shù)情況下heap_2.c是可以使用的。但是,如果分配給任務的堆棧不總是相等,那么釋放的有效內(nèi)存可能碎片化,形成很多小的內(nèi)存塊。最后會因為沒有足夠大的連續(xù)堆??臻g而造成內(nèi)存分配失敗。在這種情況下,heap_4.c是一個很好的選擇。
- 如果一個應用程序動態(tài)的創(chuàng)建和刪除隊列,并且在每種情況下隊列存儲區(qū)域(隊列存儲區(qū)域指隊列項數(shù)目乘以每個隊列長度)都是同樣的,那么大多數(shù)情況下heap_2.c可以使用。但是,如果隊列存儲區(qū)在每種情況下并不總是相等,那么釋放的有效內(nèi)存可能碎片化,形成很多小的內(nèi)存塊。最后會因為沒有足夠大的連續(xù)堆棧空間而造成內(nèi)存分配失敗。在這種情況下,heap_4.c是一個很好的選擇。
- 應用程序直接調(diào)用pvPortMalloc() 和 vPortFree()函數(shù),而不僅是通過FreeRTOS API間接調(diào)用。
如果你的應用程序中的隊列、任務、信號量、互斥量等等處在一個不可預料的順序,則可能會導致內(nèi)存碎片問題,雖然這是小概率事件,但必須牢記。
不具有確定性,但是它比標準庫中的malloc函數(shù)具有高得多的效率。
? ? ? heap_2.c適用于需要動態(tài)創(chuàng)建任務的大多數(shù)小型實時系統(tǒng)(smallreal time)。
3.heap_3.c
heap_3.c簡單的包裝了標準庫中的malloc()和free()函數(shù),包裝后的malloc()和free()函數(shù)具備線程保護。
功能簡介:
- 需要鏈接器設置一個堆棧,并且編譯器庫提供malloc()和free()函數(shù)。
- 不具有確定性
- 可能明顯的增大RTOS內(nèi)核的代碼大小
注:使用heap_3時,F(xiàn)reeRTOSConfig.h文件中的configTOTAL_HEAP_SIZE宏定義沒有作用。
4.heap_4.c
這個方案使用一個最佳匹配算法,但不像方案2那樣。它會將相鄰的空閑內(nèi)存塊合并成一個更大的塊(包含一個合并算法)。
有效的堆棧空間大小由位于FreeRTOSConfig.h文件中的configTOTAL_HEAP_SIZE來定義。
API函數(shù)xPortGetFreeHeapSize()返回剩下的未分配堆??臻g的大?。捎糜趦?yōu)化設置configTOTAL_HEAP_SIZE宏的值),但是不能提供未分配內(nèi)存的碎片細節(jié)信息。
功能簡介:
- 可用于重復分配、刪除任務、隊列、信號量、互斥量等等的應用程序。
- 可以用于分配和釋放隨機字節(jié)內(nèi)存的情況,并不像heap_2.c那樣產(chǎn)生嚴重碎片。
- 不具有確定性,但是它比標準庫中的malloc函數(shù)具有高得多的效率。
? ? ? heap_4.c還特別適用于移植層代碼,可以直接使用pvPortMalloc()和 vPortFree()函數(shù)來分配和釋放內(nèi)存。
5.heap_5.c(V8.1.0新增)
這個方案同樣實現(xiàn)了heap_4.c中的合并算法,并且允許堆??缭蕉鄠€非連續(xù)的內(nèi)存區(qū)。
Heap_5通過調(diào)用vPortDefineHeapRegions()函數(shù)實現(xiàn)初始化,在該函數(shù)執(zhí)行完成前不允許使用內(nèi)存分配和釋放。創(chuàng)建RTOS對象(任務、隊列、信號量等等)會隱含的調(diào)用pvPortMalloc(),因此必須注意:使用heap_5創(chuàng)建任何對象前,要先執(zhí)行vPortDefineHeapRegions()函數(shù)。
vPortDefineHeapRegions()函數(shù)只需要單個參數(shù)。該參數(shù)是一個HeapRegion_t結構體類型數(shù)組。HeapRegion_t在portable.h中定義,如下所示:
typedef struct HeapRegion { /* 用于內(nèi)存堆的內(nèi)存塊起始地址*/ uint8_t *pucStartAddress; /* 內(nèi)存塊大小 */ size_t xSizeInBytes; } HeapRegion_t;
這個數(shù)組必須使用一個NULL指針和0字節(jié)元素作為結束,起始地址必須從小到大排列。下面的代碼段提供一個例子。MSVCWin32模擬器演示例程使用了heap_5,因此可以當做一個參考例程。
/* 在內(nèi)存中為內(nèi)存堆分配兩個內(nèi)存塊.第一個內(nèi)存塊0x10000字節(jié),起始地址為0x80000000, 第二個內(nèi)存塊0xa0000字節(jié),起始地址為0x90000000.起始地址為0x80000000的內(nèi)存塊的 起始地址更低,因此放到了數(shù)組的第一個位置.*/ const HeapRegion_t xHeapRegions[] = { { ( uint8_t * ) 0x80000000UL, 0x10000 }, { ( uint8_t * ) 0x90000000UL, 0xa0000 }, { NULL, 0 } /* 數(shù)組結尾. */ }; /* 向函數(shù)vPortDefineHeapRegions()傳遞數(shù)組參數(shù). */ vPortDefineHeapRegions( xHeapRegions );
原文鏈接:https://blog.csdn.net/zhzht19861011/article/details/50248421
相關推薦
- 2022-07-26 SpringMVC的流程
- 2023-05-31 Pandas中map(),applymap(),apply()函數(shù)的使用方法_python
- 2022-05-25 python?序列去重并保持原始順序操作_python
- 2022-08-05 淺析C++元組tuple類型_C 語言
- 2022-07-01 python神經(jīng)網(wǎng)絡ShuffleNetV2模型復現(xiàn)詳解_python
- 2022-10-31 Flask表單與表單驗證實現(xiàn)流程介紹_python
- 2022-12-30 Golang通道channel的源碼分析_Golang
- 2023-04-08 C++對string進行大小寫轉換操作方法_C 語言
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結構-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支