0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

聊聊FreeRTOS內存管理方案及相關的優(yōu)化措施

冬至子 ? 來源:劍一二 ? 作者:劍一二 ? 2023-11-13 11:28 ? 次閱讀

FreeRTOS 作為一個嵌入式實時操作系統(tǒng),其運行的環(huán)境一般資源有限,特別是其內存資源,可能只有幾 M,甚至是幾十 KB。針對不同的應用場景,FreeRTOS 源碼中提供了 5 種內存管理方案。本文就來聊聊這些內存管理方案以及相關的優(yōu)化措施。

內存管理相關的代碼在 lib/FreeRTOS/portable/MemMang 目錄下,從 heap_1.c 到 heap_5.c,文件相互獨立,并提供統(tǒng)一接口

void *pvPortMalloc( size_t xWantedSize );
void vPortFree( void *pv );

而 heap 的定義,可以是一塊靜態(tài)分配的數組作為 heap,也可以是指定的一塊區(qū)域作為 heap,本文就以靜態(tài)數組為例進行講解。

#if( configAPPLICATION_ALLOCATED_HEAP == 1)
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif

實際上,內存釋放接口并不一定都有效,因為 heap_1 方案是不支持內存釋放的。在 heap_1 中調用 pvPortMalloc() 的時候,其具體實現如下所示:

圖片

pucAligendHeap: 對齊后的 heap 起始地址。

xNextFreeByte: 記錄下一次分配內存的偏移值,實際就是已分配內存的總大小。

pvReturn = pucAlignedHeap + xNextFreeByte;
xNextFreeByte += xWantedSize;

每次分配的時候,返回 pucAligendHeap + xNextFreeByte 的地址,然后更新 xNextFreeByte。當然了,整個分配過程中,還有一些對齊操作。由于分配后的內存不能進行釋放,所以這種分配方案適用于不需要頻繁申請釋放內存的場景。

相對于 heap_1 方案,在 heap_2 中增加了內存釋放的函數。其實現是在每一次分配的內存中增加了一些描述信息(也就是多分配一個結構體大小的內存,用于保存描述信息),這樣在釋放的時候,就可以根據這些信息回收內存。

typedef struct A_BLOCK_LINK {
    struct A_BLOCK_LINK *pxNextFreeBlock;
    size_t xBlockSize;
} BlockLink_t;

static const uint16_t heapSTRUCT_SIZE = (( sizeof( BlockLink_t ) + ( portBYTE_ALIGNMENT - 1 )) & ~portBYTE_ALIGNMENT_MASK );

xWantedSize += heapSTRUCT_SIZE;  /*每次分配的時候自動加上描述結構體的大小*/

描述信息結構體中包含了一個鏈表指針,用于在釋放的時候,將該內存加入到空閑鏈表中,每次分配內存實際就是從空閑鏈表上進行分配(初始狀態(tài),整個鏈表除了頭尾,就一個成員,就是整個空閑的 heap 塊)。xBlockSize 用于描述分配內存的大小。

圖片

其中,xStart 和 xEnd 是空閑鏈的頭尾節(jié)點。初始狀態(tài)時,整個 heap 就是一個空閑塊。分配的時候,從頭遍歷空閑鏈,找到第一個滿足大小的塊,也就是最先匹配原則(first fit),從中分裂出所需的大小,然后將剩余的插入到空閑鏈中。而釋放就是將其插入到空閑鏈中。

需要注意的是,插入空閑鏈中,都是升序排列的,也就是說在分配的時候,最先滿足的塊也是最優(yōu)的塊(best fit),可以減少碎片的產生。從實現來看,heap_2 雖然添加了釋放內存函數,但其在插入到空閑鏈的時候,沒有對相鄰的塊進行合并,所以 heap_2 適用于操作固定大小內存的場景。

heap_3 的方案沒有基于 heap_2 進行優(yōu)化,而是直接使用 libc 庫中 malloc() / free() 接口,所以這里就不多做介紹。

事實上,相鄰塊合并功能是在 heap_4 中引入的。在將空閑塊插入到鏈表的時候,會判斷是否有空閑塊是相鄰的,如果相鄰就合并成一個更大的空閑塊,就能減少碎片的產生,進而更適用于一般的內存分配和釋放場景。注意 heap_4 在插入空閑鏈的時候,不再是升序排列,而是根據地址大小進行排列,這樣便于判斷量表中前后兩個塊是否相鄰。

圖片

heap_5 相對于 heap_4 方案并沒有進行算法上的優(yōu)化,它添加了一個接口可以指定某個內存塊作為 heap。

void vPortDefineHeapRegions( const HeapRegion_t * const pRegions );

在前幾種內存管理方案中,除了 heap_3,內存塊都是靜態(tài)分配的。而在 heap_5 中 heap 不再是靜態(tài)定義的全局變量,而是需要顯示指定的一塊內存區(qū)域作為 heap。這樣的好處就是,heap 的來源更加靈活,可以是和運行空間不連續(xù)的一塊內存,也可以將多個不連續(xù)的內存塊作為 heap 進行管理。

以上就介紹了 FreeRTOS 中原生的 5 種內存管理方案。可以看出,后面的內存管理方案對前面的管理方案是兼容的,比如 heap_5 可以替代 heap_1, heap_2 和 heap_4 方案。這里可能就有個疑問了,為什么不直接用 heap_5 方案呢?更豐富的功能,意味著復雜的一些實現,在一些簡單的場景中,heap_5 分配速度可能沒有 heap_1 或者 heap_2 來得快,所以 heap_1,heap_2 等方案也有其存在的意義。

在實際場景中,比如隨機的分配和釋放,而且分配的大小也不一致,這個時候,一般會選擇 heap_4。heap_4 引入了內存合并功能,可以減少內存碎片,但和 heap_2 相比,也把最優(yōu)匹配的原則去掉了。如下圖所示:

圖片

當要分配一個 32Bytes 的內存(經過對齊等處理后的大?。凑?heap_4 的分配方案,最先匹配原則,會從 56Bytes 大小的塊中分配一個32Bytes 出去,而不是從第二個空閑塊,剛剛好是 32Bytes 的塊中分配。這樣的分配方法就會產生碎片。碎片多了就會導致空閑內存看似很多,但大的內存塊已經沒有了。

優(yōu)化的辦法也很簡單,就是遍歷整個空閑鏈表,找到最優(yōu)的一個塊,其修改方法就是在原來 first fit 的基礎上,遍歷剩余的鏈表:

/* first fit */
while ((pxBlock- >xBlockSize < xWantedSize) && (pxBlock- >pxNextFreeBlock != NULL))
{
   pxPreviousBlock = pxBlock;
   pxBlock = pxBlock- >pxNextFreeBlock;
}
/* best fit */
BlockLink_t *pxTmp = pxBlock;
BlockLink_t *pxPreTmp = pxPreviousBlock;while (pxTmp != pxEnd){
   if ((pxTmp- >xBlockSize >= xWantedSize) && (pxTmp- >xBlockSize < pxBlock- >xBlockSize))
  {
       pxBlock = pxTmp;
       pxPreviousBlock = pxPreTmp;
  }
   pxPreTmp = pxTmp;
   pxTmp = pxTmp- >pxNextFreeBlock;
}

最優(yōu)匹配的引入,不是一定就比原來的方案效果要好,因為遍歷整個空閑鏈表,會導致分配內存的時間變長。這在某些對實時要求較高的環(huán)境中就不適應了,比如在一些網絡環(huán)境中可能會因為超時而導致功能不正常。

其實分配快,內存碎片少的方法有很多,只是他們的實現成本會有所不同,一個算法不可能適用所有的場景,分配方案中也沒有哪個比哪個一定更好,找到適合應用場景的就是好的算法。這也許就是 FreeRTOS 中保留了多種分配方案的原因吧。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
收藏 人收藏

    評論

    相關推薦

    FreeRTOS內存機制詳解

    FreeRTOS是一種實時操作系統(tǒng),它提供了多種內存分配方式,包括動態(tài)內存分配和靜態(tài)內存分配。
    的頭像 發(fā)表于 12-31 16:49 ?2088次閱讀
    <b class='flag-5'>FreeRTOS</b><b class='flag-5'>內存</b>機制詳解

    第28章 FreeRTOS動態(tài)內存管理

    28.4 實驗例程說明28.5總結28.1動態(tài)內存管理介紹 FreeRTOS支持5種動態(tài)內存管理方案
    發(fā)表于 09-11 07:15

    FreeRTOS內存管理的算法解析?

    關于FreeRTOS內存管理,有人測試過它給定的算法么?會不會有內存碎片的出現,如果產品一直運行,會不會出現內存崩潰的情況。求證啊。目前用h
    發(fā)表于 07-30 11:39

    Freertos關于堆內存管理相關資料分享

    內存管理Malloc、Free防止內存碎片Freertos
    發(fā)表于 12-27 08:12

    什么是內存優(yōu)化?有那些優(yōu)化措施

    什么是內存優(yōu)化?有那些優(yōu)化措施?
    發(fā)表于 01-14 06:22

    通信設備中內存管理優(yōu)化

    通過對內存管理的分析,提出了內存優(yōu)化算法。該算法解決了通信設備中由于大量消息的發(fā)送導致內存管理
    發(fā)表于 02-21 11:42 ?22次下載

    FreeRTOS代碼剖析之1:內存管理Heap

    內存管理是一個操作系統(tǒng)的重要組成部分之一,所有應用程序都離不開操作系統(tǒng)的內存管理。因此,在剖析FreeRTOS的內核代碼之前,前對
    發(fā)表于 02-09 05:25 ?862次閱讀
    <b class='flag-5'>FreeRTOS</b>代碼剖析之1:<b class='flag-5'>內存</b><b class='flag-5'>管理</b>Heap

    FreeRTOS代碼剖析之3:內存管理Heap

    FreeRTOS8.0.1的第三個模型Heap_3,可以說是最容易理解的一個內存管理模型。因為在這個模型里,FreeRTOS直接將標準C庫中的malloc()和free()進行加工打
    發(fā)表于 02-09 05:30 ?371次閱讀

    嵌入式操作系統(tǒng)FreeRTOS內存如何管理和堆

    嵌入式操作系統(tǒng)FreeRTOS內存管理和堆
    的頭像 發(fā)表于 01-10 15:17 ?4547次閱讀
    嵌入式操作系統(tǒng)<b class='flag-5'>FreeRTOS</b><b class='flag-5'>內存</b>如何<b class='flag-5'>管理</b>和堆

    FreeRTOS高級篇7---FreeRTOS內存管理分析

    FreeRTOS操作系統(tǒng)將內核與內存管理分開實現,操作系統(tǒng)內核僅規(guī)定了必要的內存管理函數原型,而不關心這些
    發(fā)表于 01-26 17:36 ?7次下載
    <b class='flag-5'>FreeRTOS</b>高級篇7---<b class='flag-5'>FreeRTOS</b><b class='flag-5'>內存</b><b class='flag-5'>管理</b>分析

    FreeRTOS系列第8篇---FreeRTOS內存管理

    本文介紹內存管理的基礎知識,詳細源碼分析見《 FreeRTOS高級篇7---FreeRTOS內存管理
    發(fā)表于 01-26 17:56 ?17次下載
    <b class='flag-5'>FreeRTOS</b>系列第8篇---<b class='flag-5'>FreeRTOS</b><b class='flag-5'>內存</b><b class='flag-5'>管理</b>

    FreeRTOS的源碼下載

    內存管理文件在FreeRTOS\portable\MemMang文件夾下,FreeRTOS提供了五種內存
    的頭像 發(fā)表于 02-10 11:00 ?2855次閱讀
    <b class='flag-5'>FreeRTOS</b>的源碼下載

    freeRTOS源碼中內存管理方案

    freeRTOS源碼中提供了五種內存管理方案,可以說是很方便了。實際需要使用哪一種,可以根據自己項目的需要進行選擇,都是可以的。
    的頭像 發(fā)表于 02-10 11:11 ?641次閱讀

    FreeRTOS內存管理簡介

    ,比如任務創(chuàng)建函數 xTaskCreateStatic(),使用此函數創(chuàng)建任務的時候需要由用戶定義任務堆棧,我們不討論這種靜態(tài)方法。 使用動態(tài)內存管理的時候 FreeRTOS 內核在創(chuàng)建任務、隊列、信號量的時候會動態(tài)的申請 RA
    的頭像 發(fā)表于 07-30 10:26 ?571次閱讀

    FreeRTOS內存管理實現

    FreeRTOS是一個為嵌入式系統(tǒng)設計的開源實時操作系統(tǒng)。它提供了一個多任務內核和一系列功能,適合在資源受限的設備上管理實時任務和應用程序。FreeRTOS內存
    的頭像 發(fā)表于 10-10 16:17 ?783次閱讀
    <b class='flag-5'>FreeRTOS</b><b class='flag-5'>內存</b><b class='flag-5'>管理</b>實現