2012-05-29 32 views
7

我正在尋找實現一個堆分配算法在C爲一個內存受限的微控制器。我已將搜索範圍縮小到了我所知道的兩個選項,但我非常樂於接受建議,並且正在尋找來自具有此經驗的任何人的建議或意見。抗碎片微控制器堆算法

我的要求:

- 速度絕對計數,但它是一個次要問題。

-timing決定並不重要 - 要求確定性最壞情況時序代碼的任何部分都有其自己的分配方法。

- 主要要求是破碎免疫力。該設備正在運行一個lua腳本引擎,這將需要一定範圍的分配大小(在32字節塊上很重)。主要要求是該設備可以長時間運行,而不會使其堆成無法使用的狀態。

另外注意:

(僅供參考)中,我們談論的Cortex-M和PIC32部位,用存儲器範圍從128K和16MB或存儲器(重點是下端)。

- 我不想使用編譯器的堆,因爲1)我想對所有的編譯器一致的性能和2)它們的實現一般都非常簡單,是相同的或碎裂更糟。

-double間接的選項,因爲我不想fundamtnetally變化和重新驗證巨大的Lua代碼基地出來。

我的青睞途徑迄今:

1)具有二進制好友分配器,和犧牲存儲器的使用效率(四捨五入至2大小的功率)。 - 這將(根據我的理解)需要一個二叉樹的每個訂單/斌來存儲空閒節點按內存地址排序快速夥伴塊查找重新鏈接。

2)有兩個空閒塊的二叉樹,一個按大小排序,另一個按內存地址排序。 (所有的二叉樹鏈接存儲在塊本身) -分配將是最適合的,使用在表中按大小查找,然後通過地址 從其他樹中刪除該塊 - 分配將通過地址查找相鄰塊rechaining

導向軸算法也將需要所分配的塊的開始之前存儲的分配尺寸,並具有塊出去作爲2減去4的功率(或8取決於對準)。 (除非它們存儲二叉樹其他地方來跟蹤內存地址進行排序分配,我不認爲一個好的選擇)

導向軸算法需要高度平衡二叉樹的代碼。

- 算法2沒有通過舍入到2的冪來浪費內存的要求。

-In任一情況下,我將可能有由嵌套比特字段來卸載塊這個尺寸或更小,這將是不受外部碎片分配32字節的塊的固定銀行。

我的問題:

-Is有什麼理由方法1會比方法2個免疫不成?

-Are那裏,我很想念這可能符合要求的替代品?

+0

夥伴系統沒有使用二叉樹釋放,當它找到一個塊的可能夥伴。您可以根據原始塊的地址計算好友的地址。然後你檢查一下,看看這個夥伴是免費還是使用。您可以將該位置放在該區域的起始位置 - 因此您實際上不會獲得32個字節,但可能有31個可用字節。您可以通過使用免費/使用的單獨位圖來更改此設置。 Knuth描述了一個免費使用標籤位的版本 – mcdowella

+0

Yah,我只是想到了這一點。我認爲2GB的塊大小可能足夠了:)我也認爲擺脫二叉樹免費節點的作用是將每個bin/order的空閒節點存儲在一個雙鏈接的循環列表中,然後使用好友的指向鏈接下一個和前一個節點的指針(並且如果節點指向正被移除的節點,則將頭部ptr提前一個節點)。通過這種方式,根本不需要搜索來查找和刪除免費好友。因此,沒有二叉樹實現。思考? –

+0

你真的需要分配嗎?像這些嵌入式系統通常不分配,但使用固定大小的結構(當然堆棧除外,你必須小心)。給被認爲是堅如磐石的東西增加了太多的風險。 –

回答

1

如果塊尺寸不向上舍入到的兩個或一些相當的(*)的權力,分配和解除分配的某些序列會產生碎片的基本上-無限量即使存在在非永久的小物件的數目任何時間都是有限的。二進制好友分配器當然會避免這個特殊問題。否則,如果使用有限數量的相關對象大小但不使用「二進制夥伴」系統,則可能仍然需要使用一些判斷來決定在哪裏分配新塊。

另一種方法要考慮的是其對於預計將永久,臨時或半永久性的東西不同的分配方法。當臨時和永久的東西在堆上交錯時,碎片通常會造成最大的麻煩。避免這種交錯可能會使碎片最小化。

最後,我知道你真的不希望使用雙間接指針,但允許目標再配置可以大大減少碎片有關的問題。許多微軟派生的微型計算機BASIC使用垃圾收集字符串堆;微軟的垃圾收集器真的很糟糕,但是它的字符串堆方法可以使用很好的方法。

+0

確實非常有幫助!通過兩個或同等權力,你是在談論斐波那契夥伴等?你能給我一個模式的簡單例子來證明二元/其他夥伴系統的優勢嗎?我似乎無法自己想出一個...... –

+0

另外,至於雙重間接,這將涉及完全重寫lua引擎以支持雙重間接分配......也許有一個等待寫入的寶石。無論哪種方式,這將是一個可怕的驗證量。至於操作系統,它在句柄表中使用了一種雙重間接的形式,並且在流緩衝中使用了相同大小緩衝區的池,所以它實際上只是我所關心的lua。如何模擬/測試/量化內存空間碎片? –

+0

兩個夥伴的力量的一個好處是一些內存用戶碰巧需要兩個塊大小的功率 - 你提到Lua想要32個字節的塊,並且一些嵌入式系統可能想要用兩個塊大小的功率進行FFT。如果你實際上可以使用所有的兩個夥伴塊大小的功率(而不必花費一點時間來釋放/使用),那麼這是一個很好的選擇 - 這就是爲什麼我寫了一個帶有外部自由/使用位圖,只是爲了表明它可以完成。 – mcdowella

1

你可以拿起一個(從來沒有使用真正的)夥伴系統分配器在http://www.mcdowella.demon.co.uk/buddy.html,帶着我的祝福給你喜歡的任何目的。但我不認爲你的問題很容易通過插入內存分配器來解決。我熟悉的長期運行的高完整性系統具有可預測的資源使用情況,在每個資源的30多頁文檔中都有介紹(主要是cpu和I/O總線帶寬 - 內存很容易,因爲它們每次啓動時都會分配相同的數量然後再也不會)。

在你的情況下,沒有任何常用技巧 - 靜態分配,自由列表,堆棧分配,可以顯示工作,因爲 - 至少如我們所描述的 - 你有一個Lua解釋在後臺徘徊準備做誰知道在運行時什麼 - 如果它進入一個分配內存的循環,直到它用完爲止呢?

您可以將內存使用分爲兩部分 - 傳統代碼幾乎分配啓動時所需的所有內容,並且永遠不會再使用,並且可用代碼(例如Lua)允許在需要時分配任何需要的內容靜態分配後剩餘嗎?那麼如果它能夠使用所有的內存區域或碎片,而不打擾傳統代碼,那麼你能觸發一次重啓或對某些易耗代碼進行某種清理嗎?

+0

這是一個很好的觀點:在計劃重新啓動Lua引擎時進行設計,我開始認爲這是不可避免的。是的,lua分配完全是從其他內存分配中進行沙箱化。我可以確保所有其他動態內存分配的碎片免疫。我不能保證即使已知的好的lua代碼有很多備用堆,也不會慢慢地導致自己死亡。我認爲我可以即時將lua環境的全部內容從一個lua引擎序列化並遷移到另一個lua引擎,但這樣會變得瘋狂。 –