大家好,這是我第一篇在CSDN上的博文,本篇主要討論小型內存池的設計

大家好,這是我第一篇在CSDN上的博文,本人主要研究嵌入式軟件相關。
我先自我介紹一下,本人13年華南師大畢業,現在在深圳一家創業公司工作,主要做嵌入式軟件開發,開發平臺包括windows和linux,接觸使用的軟件也很多,如Codewarrior、keil、STVD、IAR、VC等,本人寫博客主要也是爲了和大家交流嵌入式技術,如有錯誤或者有其他意見也可以向我提出。
最近一個多月都在windows平臺上開發一個實時數據庫,使用C++語言,此實時數據庫的目的在於保存工控應用環境中成千上萬的數據量,實時數據庫的設計要求要有良好的文件組織,高效的壓縮算法,方便的接口以及快速的讀寫操作,要求對多個模塊操作的時間複雜度爲常數級別。
在對數據查詢、數據寫入隊列和其他操作命令隊列中,需要經常分配和回收內存,使用系統自帶的new來分配內存,如果只是小量內存的快速分配和回收,那效率也還可以,但是很多情況下並非滿足這樣的條件,例如,在對數據查詢的時候,如果一個點位保存了成年累月的數據,那麼查詢出來的數據量無疑是非常龐大而且耗時較長,如果用new來分配內存,到了上萬條數據時(在本人機器上大概是1.5萬條數據),new的效率明顯的下降,分配1.5萬條數據內存需要消耗4秒的時間,如果是多線程環境下更長。光是分配內存就要消耗大部分時間,當然這只是單純的分配,如果還有構造鏈表之如的操作,那查詢的數據的操作在內存上消耗的時間也佔用了大部分,還不算上讀寫文件的操作(之後會有一篇文章討論文件的讀寫)。因此需要構造一個內存池來管理這些內存的回收和釋放。
本人蔘考了網上一些高人寫的內存池代碼,各有春秋,分析整理後,本人的內存池設計如下:
先來個圖顯示設計結構

內存塊示意圖

這裏分配的內存是以4字節的倍數去分配的,也就是說分配的內存有可能是多出幾個字節,對於現在的計算機來說,多出這幾個字節也不算是什麼問題,後面還會提到,這裏的實現是要犧牲一定的內存爲代價來達到快速分配的效果。首先使用一個數組來保存這些內存分配信息,可以注意到,這裏最大分配的是1024的字節,內存池分配的原則是,少於1024的字節使用內存池分配,多於1024的字節直接使用new來進行分配,這裏可以靈活設置,如果內存夠大,可以把1024弄成其他也可以,不過我建議,如果一次需要分配這個量的內存,機使用new來更加划算,因爲如果最大的分配內存設置太大,則內存池需要爲其一次建立一定量的內存塊,這樣內存佔用量突然會很高,需要根據實際情況權衡。這裏主要討論的是小塊內存的快速分配和釋放,大內存塊的分配可以參考其他高人的代碼,這裏也不再討論。
當有一個分配內存的請求來時,假如需要申請的內存爲253的內存,根據內存池的分配原則,找到下標爲253/4+1 = 64的下標,找到對應的內存分配描述信息,從空閒內存鏈表頭中取出內存塊,然後讓其加到使用鏈表的隊尾,如圖所示。
內存塊鏈表變換
然後返回這個內存塊中的數據內存指針
這裏需要說明一點,每個內存塊的成員如下
struct MemBlock
{
MemBlock* next;//下一個塊
MemBlock* pre;//前一個塊
void* data;//數據內存塊
int index;//所屬內存描述的下標
};
這裏的data+4纔是返回給用戶使用的內存塊,爲什麼是加4呢?這裏多分配了4個字節,用來存儲這個data所屬的MemBlock指針,這裏就是剛纔提到的空間換取時間的概念,這樣當我們回收內存的時候能找到對應的MemBlock,從而完成回收,回收過程如下
這裏寫圖片描述

最主要的還是操作各指針的指向,一用到指針操作則非常容易出錯,本人也是調試了3天左右,才把這個內存池調穩定,測試情況如下,
本人機器爲Inter i3處理器,4G的內存,使用new對10萬條數據連續分配和回收的情況下(包含鏈表的壓入和彈出的操作),使用時間大概爲4秒左右,使用內存池進行分配和回收,所用時間不到300ms,效率有極大的提升。

結尾:本文介紹了一款小型內存池的設計,主要解決在應用中對於小內存塊大量分配和回收情況造成內存碎片和分配速度緩慢問題,經測定能耐有效講的new帶來的時間開銷,大家有什麼修改意見的話可以提出來,本人也虛心接納,如果需要源碼可以在留言或者私信中跟我說,下一篇討論線程池的實現,謝謝大家的閱讀。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章