在象通信系統中的基站這樣的複雜嵌入式系統中,對於內存管理模塊的效率具備很高的要求,所以內存管理模塊的算法頗有講究。講究在於,不只要考慮算法的效率,還要兼顧算法是否會帶來大量的內存碎片以及如何進行內存碎片合併。正因如此,這類嵌入式系統軟件大多會對內存管理模塊根據業務特色進行適當的優化。
優化的方式無外乎引入內存池,或對堆管理模塊引入新的算法加以優化,然而這些方法除了引入了必定的算法複雜度外,仍存在不小的改善空間。藉此,做者想提出一種面向業務流的內存管理算法與你們共同探討。
爲了討論的方便性,咱們假設某虛擬系統存在以下的業務流順序圖。圖中的三個模塊只是表明性的,它們便可以指以消息爲通信手段的三個任務,也能夠指存在函數調用關係的三個模塊。圖中的紅色消息表示存在處理的過程當中需進行內存分配的操做,並假設所分配出來的內存在消息的後續處理中須要用到。好比,處理MsgA時所分配的內存可能須要被ModuleB和ModuleC使用,且該內存在處理完MsgA後須要釋放。值得一提的是,這個虛擬系統存在大量的併發業務流須要處理(這比如機站中存在多個電話呼叫信令須要同時處理)。
對於這樣的業務流,最爲傳統的內存使用方法是分別在處理MsgA和MsgB時調用內存分配函數獲取內存,並將所得到的內存指針經過消息攜帶的方式傳遞給後續模塊處理。當系統複雜(一個消息的後續處理模塊數很是多),且所分配的內存在大小上存在不小差異時,分配和釋放內存的效率及內存碎片問題或成爲系統的瓶頸,加以內存的分配與釋放功能是分散在不一樣的模塊中的,於是容易產生內存泄漏。
如今讓咱們跳出這種使用內存的傳統思惟,站在業務流的角度從新審視內存的使用方法。不難發現,對於一個業務流,處理MsgA和MsgB所分配的內存儘管存在分配時機上的區別,但它們都共同服務於同一業務流。既然如此,咱們爲什麼不將內存的分配與釋放時機放在業務流的開始與結束處呢?好比,在處理MsgA時將MsgB所需的內存也分配好,全部分配的內存也能夠在業務流結束後共同釋放。採用這種方式須要解決一個問題,既在處理MsgA時須要知道處理MsgB時所需分配內存的大小。顯然,不能簡單地將處理MsgB的部分功能挪處處理MsgA的功能塊中,由於這可能會破壞程序結構。簡易的解決方法能夠經過犧牲必定的內存得到 — 經過分析業務流,咱們能夠知道處理某消息所需分配內存的最大值,進而用那個最大值做爲在處理MsgA時所需提早分配的數量。(注:若是內存的大小存在很大的差別,做者建議結合採用傳統方法,而非徹底採用後面將要談到的方法)
至此,咱們邁出了很重要的一種思路轉變,爲了得到方便的實現方法咱們仍需更進一步。若是一個業務流中各處所需分配的內存大小能預先以取最大值的方式肯定下來加以規劃,咱們就能夠經過必定的數據結構來表達,以下圖所示。
-
#define MAX_SIZE_FOR_MSGA 32
-
#define MAX_SIZE_FOR_MSGB 128
-
-
typedef struct
-
{
-
char forMsgA [MAX_SIZE_FOR_MSGA];
-
char forMsgB [MAX_SIZE_FOR_MSGB];
-
} business_flow_memory_t;
-
-
#define CONFIG_MAX_BUSINESS_FLOW_SUPPORTED 900
-
-
business_flow_memory_t g_memory_pool [CONFIG_MAX_BUSINESS_FLOW_SUPPORTED];
相信圖中的前部分代碼非常直截了當,後部分代碼則假設系統最多同時支持900個業務流須要處理。當一個新的業務流須要處理時(在這裏的例子中,處理MsgA時),直接從g_business_memory_pool數組中獲取一個元素,以做處理整個業務流所需的所有內存(能夠設想,這一內存會在業務流的不一樣處理階段被使用);當結束一個業務流時(在這裏的例子中,處理完MsgA後),則能夠經過一次性地釋放該元素從而完成內存釋放。顯然,數組元素的獲取與釋放須要爲這提供相應的函數,且對元素的管理能夠考慮引入鏈表等方法以提升管理效率。這部份內容咱們在此不展開。
致此相信讀者已瞭解面向業務流內存管理算法的機理了。做爲結束,咱們應總結一下這一算法的優缺點。優勢有:一,分配與釋放很是高效,且不會隨着系統的運行而產生任何內存碎片;二,很容易杜絕內存泄漏。缺點有:一,因爲每處使用的內存需以最大值進行規劃,存在必定的內存浪費;二,當之內存所需最大值進行規劃存在嚴重的內存浪費時,該算法存在適用性問題。再囉嗦一下,若有適用性問題時,請運用傳統使用內存的方法(調用malloc/free)與這裏所主張的方法相結合加以解決。