我遇到的許多嵌入式軟件開(kāi)發(fā)人員提出的一個(gè)我覺(jué)得特別有趣的話題是動(dòng)態(tài)內(nèi)存分配——在需要時(shí)獲取內(nèi)存塊。這種看似簡(jiǎn)單和常規(guī)的操作會(huì)帶來(lái)大量問(wèn)題。這些并不局限于嵌入式開(kāi)發(fā)——許多桌面應(yīng)用程序都會(huì)出現(xiàn)內(nèi)存泄漏,這會(huì)影響性能,并且會(huì)使系統(tǒng)重新啟動(dòng)很常見(jiàn)。但是,我擔(dān)心嵌入式開(kāi)發(fā)環(huán)境。
通常不建議將malloc()用于嵌入式應(yīng)用程序的原因有很多:
- 該函數(shù)通常不可重入(線程友好),因此將其與實(shí)時(shí)操作系統(tǒng)一起使用可能具有挑戰(zhàn)性。
- 它的性能不是確定性的(可預(yù)測(cè)的),因此分配一個(gè)內(nèi)存塊所花費(fèi)的時(shí)間可能是非常可變的,這在實(shí)時(shí)應(yīng)用程序中是一個(gè)挑戰(zhàn)。
- 內(nèi)存分配可能會(huì)失敗。
盡管這些都是有效的觀點(diǎn),但它們可能并不像看起來(lái)那么重要。
僅當(dāng)從多個(gè)線程調(diào)用函數(shù)時(shí),重入才是一個(gè)問(wèn)題。編寫(xiě)一個(gè)可重入的malloc()函數(shù)是非常可行的,但也可以使用標(biāo)準(zhǔn)版本以使重入變得不必要。只需將所有內(nèi)存分配活動(dòng)本地化為單個(gè)任務(wù)。您甚至可以創(chuàng)建一個(gè)唯一功能是動(dòng)態(tài)內(nèi)存分配的任務(wù);其他任務(wù)將簡(jiǎn)單地發(fā)送一條消息,請(qǐng)求分配或釋放內(nèi)存塊。
并不總是需要確定性。并非應(yīng)用程序是實(shí)時(shí)的,并且那些不一定需要對(duì)其操作的所有部分確定性的應(yīng)用程序。
分配失敗可能是個(gè)問(wèn)題,但可以管理。如果malloc()函數(shù)無(wú)法分配所請(qǐng)求的內(nèi)存,則它會(huì)返回一個(gè)空指針。必須檢查此響應(yīng)并采取適當(dāng)?shù)拇胧?/font>如果失敗是由于內(nèi)存耗盡,很可能是設(shè)計(jì)缺陷——沒(méi)有為堆分配足夠的內(nèi)存。然而,分配失敗的一個(gè)常見(jiàn)原因是堆碎片。有足夠的可用內(nèi)存,但它不在連續(xù)區(qū)域中。這種碎片的出現(xiàn)是因?yàn)閮?nèi)存以隨機(jī)方式分配和釋放,從而導(dǎo)致內(nèi)存的分配和空閑區(qū)域。有兩種方法可以消除碎片:
首先,如果應(yīng)用程序允許,只需確保使用遵循這種模式的代碼按順序完成分配和釋放:
a = malloc(1000); b = malloc(100); c = malloc(5000); ... 免費(fèi)(c); 免費(fèi)(乙); 免費(fèi)(一);
當(dāng)然,這通常是不可能的。因此,需要另一種選擇。
事實(shí)證明,許多應(yīng)用程序并不需要malloc()提供的所有靈活性。所需的內(nèi)存塊具有固定大小(或少量不同大小)。為固定大小的塊編寫(xiě)內(nèi)存分配器非常簡(jiǎn)單;這消除了碎片化,如果需要,可以很容易地確定性。毫不奇怪,大多數(shù) RTOS 都有以這種方式分配內(nèi)存塊的服務(wù)調(diào)用。
不管它的不可預(yù)測(cè)性如何, malloc()還有另一個(gè)問(wèn)題——它往往相當(dāng)慢。這并不奇怪,因?yàn)樵摵瘮?shù)的功能非常復(fù)雜。基于塊的分配器的內(nèi)在簡(jiǎn)單性非常有效地解決了這個(gè)問(wèn)題。
但是,如果應(yīng)用程序在不可預(yù)測(cè)的時(shí)間確實(shí)需要隨機(jī)大小的內(nèi)存塊怎么辦?
實(shí)現(xiàn)這種靈活性同時(shí)避免碎片和不確定性的一種方法是構(gòu)建一個(gè)分配器,根據(jù)請(qǐng)求的內(nèi)存塊大小從多個(gè)“池”中選擇塊。為池選擇塊大小的一個(gè)好方法(如果您事先不知道需要的塊大小)是使用幾何系列,如 16、32、64、128 字節(jié)。然后分配將像這樣工作:
顯然,一些分配會(huì)非常有效:16 字節(jié)池中的 16 字節(jié)。有些會(huì)非常好;來(lái)自 32 字節(jié)池的 31 個(gè)字節(jié)。其他人會(huì)沒(méi)事的;來(lái)自 16 字節(jié)池的 9 個(gè)字節(jié)。還有一些效率低下;來(lái)自 128 字節(jié)池的 65 個(gè)字節(jié)。總體而言,這些低效率是為速度、確定性和消除碎片化的好處付出的小代價(jià)。
審核編輯:湯梓紅
-
嵌入式
+關(guān)注
關(guān)注
5082文章
19104瀏覽量
304797 -
應(yīng)用程序
+關(guān)注
關(guān)注
37文章
3265瀏覽量
57677 -
內(nèi)存分配
+關(guān)注
關(guān)注
0文章
16瀏覽量
8301
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論