回答

11

在嵌入式系統中,您的內存非常有限。因此,如果你偶爾只丟失一個字節的內存(因爲你分配了內存,但你沒有釋放內存),這會很快耗盡系統內存(1 GB內存,泄漏率爲1 /小時)如果你擁有4kB的內存,那麼不會太長)

本質上,避免動態內存的行爲是爲了避免程序中的bug的影響。由於靜態內存分配是完全確定性的(而動態內存分配不是),所以通過僅使用靜態內存分配,可以抵消這些錯誤。其中一個重要因素是嵌入式系統通常用於安全關鍵型應用程序。幾小時的停機時間可能花費數百萬美元,或者可能發生事故。此外,根據動態內存分配器,不確定性也可能需要不確定的時間量,這可能導致更多的錯誤,尤其是在依賴緊時序的系統中(感謝Clifford提到這一點)。這種類型的bug通常很難測試和重現,因爲它依賴於一個非常具體的執行路徑。

此外,嵌入式系統通常不會有MMU,所以沒有任何內存保護。如果內存不足,並且處理該條件的代碼不起作用,那麼最終可能會執行任何內存(可能會發生錯誤!但這種情況僅與動態內存分配有關)。

由於提到Hao Shen,碎片也是一種危險。它是否會發生取決於您的確切用例,但在嵌入式系統中,由於碎片導致50%的內存很容易丟失。如果您分配始終具有完全相同大小的塊,則只能避免碎片。

性能也起作用(取決於用例 - 謝謝Hao Shen)。靜態分配的內存由編譯器分配,而malloc()等需要在設備上運行,因此消耗CPU時間(和功耗)。

許多嵌入式操作系統(例如ChibiOS)都支持某種動態內存分配器。但使用它只會增加出現意外問題的可能性。

請注意,這些參數通常通過使用較小的靜態分配的內存池來繞過。這不是一個真正的解決方案,因爲這些池中的內存仍可能耗盡,但它只會影響系統的一小部分。

正如Stephano Sanfilippo所指出的,有些系統甚至沒有足夠的資源來支持動態內存分配。

注:大多數編碼標準,包括the JPL coding standardDO-178B(爲至關重要的航空代碼 - 感謝[Stephano聖菲利波])(https://stackoverflow.com/users/2344584/stefano-sanfilippo)禁止使用malloc。

我還假設MISRA C standard禁止malloc()因爲this forum post - 但我沒有訪問標準本身。

+0

只是舉一個實際的例子,DO-178B美國軍標禁止在安全關鍵的嵌入式航空電子代碼中使用'malloc'。 –

+0

嗨烏利感謝您的信息。我相信碎片會浪費寶貴的內存在嵌入式系統。但你認爲速度也是一個問題嗎?也許使用更小的靜態分配內存更快? –

+0

@霍申是的,我同意!如果發生碎片取決於你的用例,但OP特別要求*不同大小的內存*。我將編輯到我的答案! –

5

的主要原因不使用動態堆內存分配這裏基本上是:

一個)決定論,相關, b)中內存碎片。

內存泄漏在這些小型嵌入式應用程序中通常不是問題,因爲它們將在開發/測試中很早被發現。

但是,內存碎片可能會變得不確定,導致(最好的​​情況下)在應用程序的隨機時間和點處發生內存不足錯誤。

在動態分配的開發過程中預測應用程序的實際最大內存使用量也可能不是微不足道的,而靜態分配的內存量在編譯時是已知的,檢查內存是否可以是絕對微不足道的由硬件提供還是不提供。

+0

+1對於決定論,但解釋缺少一個重要的考慮因素:在實時系統中,非確定性行爲關注的是需要變量和無限時間長度的操作,而不管它們是失敗還是成功。典型的「首次擬合」內存分配無法在固定時間內找到塊,因此實時任務可能會錯過最後期限。動態存儲器不應該用在嵌入式系統中,而不應該用於實時處理。 – Clifford

+1

@Clifford感謝有關不確定時間的建議。我在我的答案中編輯了它。即使對於非RT系統,我也傾向於不使用動態memalloc(如果可能的話),因爲缺少確定性和泄漏內存的風險。 –

+0

@Clifford這不僅僅是一個確定性時間表問題。當內存碎片化時,如果沒有MMU,即使總體上有足夠的內存可用,特定的'malloc'調用可能會成功或失敗,這取決於應用程序之前遇到的事件的歷史記錄。這使得很難預測在現場系統中是否需要分配內存。 – JimmyB

3

從固定大小的塊中分配內存與動態內存分配相比具有一些優點。它可以防止堆碎片,並且更具確定性。

使用動態內存分配,動態大小的內存塊將從固定大小的堆中分配。分配不一定按照分配的順序釋放。隨着時間的推移,這可能導致堆中空閒部分在堆的分配部分之間分配的情況。隨着這種碎片化的發生,滿足更大的內存分配請求可能變得更加困難。如果請求進行大量內存分配,並且堆中沒有連續的空閒部分足夠大,則分配將失敗。堆可能有足夠的可用內存空間,但如果它全部分段並且沒有連續的部分,則分配將失敗。在嵌入式系統中,由於堆碎片導致malloc()失敗的可能性不理想。

解決碎片問題的一種方法是在釋放較小的內存分配時將其重新分配到更大的連續部分。這可以通過各種方式完成,但都需要時間並且可以使系統不那麼確定。例如,如果內存管理器在釋放內存分配時掃描堆,那麼完成free()所花費的時間量可能會有所不同,具體取決於正在釋放的分配的相鄰內存類型。在許多嵌入式系統中,這是非確定性和不可取的。

從固定大小的塊分配池不會導致碎片。只要有一些空閒的塊,那麼分配不會失敗,因爲每個塊都是合適的大小。加分配和釋放固定大小的池塊更簡單。所以分配函數和自由函數可以寫成確定性的。

+0

感謝您的回覆。你說「從一個固定大小的塊分配池不會導致碎片」。雖然我知道這是真的,但其實我並不完全明白。如果我理解正確,隨着時間的推移,仍然會有一些零散的小固定大小的塊,對吧?大內存請求仍然無法使用它們,對嗎? –

+2

@HaoShen,當你使用一個固定大小的塊時,你必須設計你的應用程序來分配只有特定大小的塊。你的應用程序不應該請求更大(或更小)的塊。所以,如果有任何塊可用,那麼它們總是正確的大小。這可以防止正確完成時的碎片。 – kkrambo

相關問題