如何高效管理MCU的內(nèi)存? 6種分配算法對比
本文主要介紹內(nèi)存的基本概念以及操作系統(tǒng)的內(nèi)存管理算法。
內(nèi)存的基本概念
內(nèi)存是計算機系統(tǒng)中除了處理器以外最重要的資源,用于存儲當前正在執(zhí)行的程序和數(shù)據(jù)。內(nèi)存是相對于CPU來說的,CPU可以直接尋址的存儲空間叫做內(nèi)存,CPU需要通過驅(qū)動才能訪問的叫做外存。
ROM RAM Flash
內(nèi)存一般采用半導體存儲單元,分為只讀存儲器(ROM,Read Only Memory)、隨機存儲器(RAM,Random Access Memory)ROM一般只能讀取不能寫入,掉電后其中的數(shù)據(jù)也不會丟失。RAM既可以從中讀取也可以寫入,但是掉電后其中的數(shù)據(jù)會丟失。內(nèi)存一般指的就是RAM。
ROM在嵌入式系統(tǒng)中一般用于存儲BootLoader以及操作系統(tǒng)或者程序代碼或者直接當硬盤使用。近年來閃存(Flash)已經(jīng)全面代替了ROM在嵌入式系統(tǒng)中的地位,它結(jié)合了ROM和RAM的長處,不僅具備電子可擦除可編程的特性,而且斷電也不會丟失數(shù)據(jù),同時可以快速讀取數(shù)據(jù)。
兩類內(nèi)存管理方式
從分配內(nèi)存是否連續(xù),可以分為兩大類。
連續(xù)內(nèi)存管理:
為進程分配的內(nèi)存空間是連續(xù)的,但這種分配方式容易形成內(nèi)存碎片(碎片是難以利用的空閑內(nèi)存,通常是小內(nèi)存),降低內(nèi)存利用率。連續(xù)內(nèi)存管理主要分為單一連續(xù)內(nèi)存管理和分區(qū)式內(nèi)存管理兩種。
非連續(xù)內(nèi)存管理:
將進程分散到多個不連續(xù)的內(nèi)存空間中,可以減少內(nèi)存碎片,內(nèi)存使用率更高。如果分配的基本單位是頁,則稱為分頁內(nèi)存管理;如果基本單位是段,則稱為分段內(nèi)存管理。
當前的操作系統(tǒng),普遍采用非連續(xù)內(nèi)存管理方式。不過因為分配粒度較大,對于內(nèi)存較小的嵌入式系統(tǒng),一般采用連續(xù)內(nèi)存管理。本文主要對嵌入式系統(tǒng)中常用的連續(xù)內(nèi)存管理的分區(qū)式內(nèi)存管理進行介紹。
分區(qū)式內(nèi)存管理
固定分區(qū):
事先就把內(nèi)存劃分為若干個固定大小的區(qū)域。分區(qū)大小既可以相等也可以不等。固定分區(qū)易于實現(xiàn),但是會造成分區(qū)內(nèi)碎片浪費,而且分區(qū)總數(shù)固定,限制了可以并發(fā)執(zhí)行的進程數(shù)量。
動態(tài)分區(qū):
根據(jù)進程的實際需要,動態(tài)地給進程分配所需內(nèi)存。
動態(tài)分區(qū)式內(nèi)存管理
First Fit (首次適應算法)
First Fit要求空閑分區(qū)鏈表以地址從小到大的順序連接。分配內(nèi)存時,從鏈表的第一個空閑分區(qū)開始查找,將最先能夠滿足要求的空閑分區(qū)分配給進程。
Next Fit (循環(huán)首次適應算法)
Next Fit由First Fit算法演變而來。分配內(nèi)存時,從上一次剛分配過的空閑分區(qū)的下一個開始查找,直至找到能滿足要求的空閑分區(qū)。查找時會采用循環(huán)查找的方式,即如果直到鏈表最后一個空閑分區(qū)都不能滿足要求,則返回到第一個空閑分區(qū)開始查找。
Best Fit (最佳適應算法)
從所有空閑分區(qū)中找出能滿足要求的、且大小最小的空閑分區(qū)。為了加快查找速度,Best Fit算法會把所有空閑分區(qū)按其容量從小到大的順序鏈接起來,這樣第一次找到的滿足大小要求的內(nèi)存必然是最小的空閑分區(qū)。
Worst Fit (最壞適應算法)
從所有空閑分區(qū)中找出能滿足要求的、且大小最大的空閑分區(qū)。Worst Fit算法按其容量從大到小的順序鏈接所有空閑分區(qū)。
Two LevelSegregated Fit (TLSF)
使用兩層鏈表來管理空閑內(nèi)存,將空閑分區(qū)大小進行分類,每一類用一個空閑鏈表表示,其中的空閑內(nèi)存大小都在某個特定值或者某個范圍內(nèi)。這樣存在多個空閑鏈表,所以又用一個索引鏈表來管理這些空閑鏈表,該表的每一項都對應一種空閑鏈表,并記錄該類空閑鏈表的表頭指針。
圖中,第一層鏈表將空閑內(nèi)存塊的大小根據(jù)2的冪進行分類。第二層鏈表是具體的每一類空閑內(nèi)存塊按照一定的范圍進行線性分段。
比如25這一類,以23即8分為4個內(nèi)存區(qū)間
【25,25+8),
【25+8,25+16),
【25+16,25+24),
【25+24,25+32);
216這一類,以214分為4個小區(qū)間
【216,216+214),
【216+214,216+2*214),
【216+2*214,216+3*214),
【216+3*214,216+4*214)。
Buddysystems(伙伴算法)
Segregated Fit算法的變種,具有更好的內(nèi)存拆分和回收合并效率。伙伴算法有很多種類,比如BinaryBuddies,F(xiàn)ibonacci Buddies等。Binary Buddies是最簡單也是最流行的一種,將所有空閑分區(qū)根據(jù)分區(qū)的大小進行分類,每一類都是具有相同大小的空閑分區(qū)的集合,使用一個空閑雙向鏈表表示。BinaryBuddies中所有的內(nèi)存分區(qū)都是2的冪次方。
因為無論是已分配的或是空閑的分區(qū),其大小均為 2 的冪次方,即使進程申請的內(nèi)存小于分配給它的內(nèi)存塊,多余的內(nèi)存也不會再拆分出來給其他進程使用,這樣就容易造成內(nèi)部碎片。
當進程申請一塊大小為n的內(nèi)存時的分配步驟為:
計算一個i值,使得2i-1<n≤2i。
在空閑分區(qū)大小為2i的空閑鏈表中查找。
如果找到空閑塊,則分配給進程。
如果2i的空閑分區(qū)已經(jīng)耗盡,則在分區(qū)大小為2i+1的空閑鏈表中查找。
如果存在2i+1的空閑分區(qū),則將此空閑塊分為相等的兩個分區(qū),這兩分區(qū)就是一對伙伴,其中一塊分配給進程,另一塊掛到分區(qū)大小為2i的空閑鏈表中。
如果2i+1的空閑分區(qū)還是不存在,則繼續(xù)查找大小為2i+2的空閑分區(qū)。如果找到,需要進行兩次拆分。第一次拆分為兩塊大小為2i+1的分區(qū),一塊分區(qū)掛到大小為2i+1的空閑鏈表中,另一塊分區(qū)繼續(xù)拆分為兩塊大小為2i的空閑分區(qū),一塊分配給進程,另一塊掛到大小為2i的空閑鏈表中。
如果2i+2的空閑分區(qū)也找不到,則繼續(xù)查找2i+3,以此類推。
| 內(nèi)存算法 |
優(yōu)點 |
缺點 |
| First Fit | 高地址空間大空閑塊被保留 | 低地址空間被不斷拆分,造成碎片;每次都從第一個空閑分區(qū)開始查找,增加了查找時的系統(tǒng)開銷 |
| Next Fit | 空閑分區(qū)分布比較均勻,算法開銷小 | 缺乏大內(nèi)存空閑塊 |
| Best Fit | 用最小內(nèi)存滿足要求,保留大內(nèi)存空閑塊 | 每次分配后所拆分出來的剩余空閑內(nèi)存總是最小的,造成許多小碎片,算法開銷大 |
| Worst Fit | 每次分配后所拆分出來的剩余空閑內(nèi)存仍較大,減少小碎片產(chǎn)生 | 缺乏大內(nèi)存空閑塊,算法開銷大 |
| TLSF | 查找效率高,時間復雜度小,碎片問題表現(xiàn)良好 | 內(nèi)存回收時算法復雜,系統(tǒng)開銷大 |
| Buddy systems | 內(nèi)部碎片比較嚴重 | 外部碎片較少 |
*本文轉(zhuǎn)自LiteOS物聯(lián)網(wǎng)操作系統(tǒng),版權(quán)歸原作者所有,如有侵權(quán)請聯(lián)系刪除
工程師必備
- 項目客服
- 培訓客服
- 平臺客服
TOP




















