我遇到的許多嵌入式軟件開發人員提出的一個我覺得特別有趣的話題是動態內存分配——在需要時獲取內存塊。這種看似簡單和常規的操作會帶來大量問題。這些并不局限于嵌入式開發——許多桌面應用程序都會出現內存泄漏,這會影響性能,并且會使系統重新啟動很常見。但是,我擔心嵌入式開發環境。

通常不建議將malloc()用于嵌入式應用程序的原因有很多:
- 該函數通常不可重入(線程友好),因此將其與實時操作系統一起使用可能具有挑戰性。
- 它的性能不是確定性的(可預測的),因此分配一個內存塊所花費的時間可能是非常可變的,這在實時應用程序中是一個挑戰。
- 內存分配可能會失敗。
盡管這些都是有效的觀點,但它們可能并不像看起來那么重要。
僅當從多個線程調用函數時,重入才是一個問題。編寫一個可重入的malloc()函數是非常可行的,但也可以使用標準版本以使重入變得不必要。只需將所有內存分配活動本地化為單個任務。您甚至可以創建一個唯一功能是動態內存分配的任務;其他任務將簡單地發送一條消息,請求分配或釋放內存塊。
并不總是需要確定性。并非應用程序是實時的,并且那些不一定需要對其操作的所有部分確定性的應用程序。
分配失敗可能是個問題,但可以管理。如果malloc()函數無法分配所請求的內存,則它會返回一個空指針。必須檢查此響應并采取適當的措施。如果失敗是由于內存耗盡,很可能是設計缺陷——沒有為堆分配足夠的內存。然而,分配失敗的一個常見原因是堆碎片。有足夠的可用內存,但它不在連續區域中。這種碎片的出現是因為內存以隨機方式分配和釋放,從而導致內存的分配和空閑區域。有兩種方法可以消除碎片:
首先,如果應用程序允許,只需確保使用遵循這種模式的代碼按順序完成分配和釋放:
a = malloc(1000); b = malloc(100); c = malloc(5000); ... 免費(c); 免費(乙); 免費(一);
當然,這通常是不可能的。因此,需要另一種選擇。
事實證明,許多應用程序并不需要malloc()提供的所有靈活性。所需的內存塊具有固定大小(或少量不同大小)。為固定大小的塊編寫內存分配器非常簡單;這消除了碎片化,如果需要,可以很容易地確定性。毫不奇怪,大多數 RTOS 都有以這種方式分配內存塊的服務調用。
不管它的不可預測性如何, malloc()還有另一個問題——它往往相當慢。這并不奇怪,因為該函數的功能非常復雜。基于塊的分配器的內在簡單性非常有效地解決了這個問題。
但是,如果應用程序在不可預測的時間確實需要隨機大小的內存塊怎么辦?
實現這種靈活性同時避免碎片和不確定性的一種方法是構建一個分配器,根據請求的內存塊大小從多個“池”中選擇塊。為池選擇塊大小的一個好方法(如果您事先不知道需要的塊大小)是使用幾何系列,如 16、32、64、128 字節。然后分配將像這樣工作:

顯然,一些分配會非常有效:16 字節池中的 16 字節。有些會非常好;來自 32 字節池的 31 個字節。其他人會沒事的;來自 16 字節池的 9 個字節。還有一些效率低下;來自 128 字節池的 65 個字節。總體而言,這些低效率是為速度、確定性和消除碎片化的好處付出的小代價。
審核編輯:湯梓紅
-
嵌入式
+關注
關注
5138文章
19524瀏覽量
314691 -
應用程序
+關注
關注
38文章
3322瀏覽量
58698 -
內存分配
+關注
關注
0文章
17瀏覽量
8405
發布評論請先 登錄
內存的動態內存分配實現
嵌入式C語言動態內存分配
請問使用動態內存分配安全嗎?
基于Core的動態內存分配方案

評論