2009-11-12 27 views
13

因此,在明年我參加uni的嵌入式系統單元中,我們將瞭解到動態數據結構在嵌入式系統程序中是一件壞事。 但講座筆記並未涉及原因。在嵌入式系統上使用動態數據結構有多糟?

現在我工作的一個規模適中,嵌入式系統\「LURC」控制器,大多隻是採取了「蝴蝶」的演示板爲AVR169MEGA的周邊的優勢。 產生4個PWM信號來控制伺服和ESC。並提供9段液晶顯示屏。

現在我想不出anybetter的方式來存儲說明,它們收到小瓶串行USART,比隊列。特別是對於需要等待接收到未知量的數據的情況:例如要在LCD屏幕上顯示的字符串。

那你爲什麼不在嵌入式系統的微控制器上使用動態數據結構? 難道你只是在一個嚴重記憶受限的環境中,並且必須確定你的malloc成功了嗎?

+1

這個:http://www.nongnu.org/avr-libc/user-manual/malloc.html很安靜 – 2009-11-12 23:03:20

回答

18

在嵌入式系統中有很多原因不使用malloc(或等價物)。

  • 正如你所提到的,重要的是你不要突然發現自己內存不足。
  • 碎片化 - 嵌入式系統可能會運行多年,這可能會導致嚴重的碎片浪費。
  • 不是必需的。動態內存分配允許您在不同的時間重複使用相同的內存來完成不同的事情。嵌入式系統往往會一直做同樣的事情(啓動時除外)。
  • 速度。動態內存分配要麼相對較慢(而且會隨着內存碎片化而變慢),要麼相當浪費(如夥伴系統)。
  • 如果您打算爲不同的線程和中斷使用相同的動態內存,則分配/釋放例程需要執行鎖定,這可能會導致問題足夠快地服務於中斷。
  • 動態內存分配使得調試非常困難,特別是在嵌入式系統上提供的一些有限/基本調試工具的情況下。如果你靜態地分配東西,那麼你就知道東西在哪裏,這意味着檢查某件東西的狀態要容易得多。

最重要的是 - 如果你不動態分配內存,那麼你不能得到內存泄漏。

+0

雖然我接受這個答案,但它仍然不完善。因爲它錯過了其中一個重要原因。 (但是大多數其他) 動態分配的內存可以非常容易地覆蓋CPU堆棧。 – 2010-02-04 04:42:25

+1

「動態分配的內存很容易覆蓋CPU堆棧。」 - 這不是真的。事實上,它是*堆棧*本質上是動態的,可能會越來越多地覆蓋另外分配的內存。非堆棧內存將爲動態和靜態分配設置一個上限,但是當堆棧增長超出預期時,它只會覆蓋它不應該的數據,不管是靜態分配還是其他。使用動態分配時,堆棧沒有更多的威脅。 – JimmyB 2014-01-26 22:59:11

0

我會說缺乏內存和malloc失敗的問題。後者更成爲一個問題,因爲您沒有OS /接口來挽救系統出現這種故障。使用一個函數可能會讓你的整個系統可能無法進入尖銳的停頓(或者可能導致重置,仍然不好)是非常危險的。

4

好,許多小微控制器不具備像一個MMU,還是一個不錯的堆你一起工作的OS事情。

對於那些做什麼,只要你繼續綁定在你所要求的內存量神志清醒,我真的沒有看到它一個巨大的問題。

然而,許多嵌入式系統也實時系統。如果您的應用程序需要很長時間才能運行,您將遇到動態分配問題。大多數堆實現使用沒有很好運行時的算法。在一些(也許很少見)的情況下,他們會比平時花更多的時間跑。有一些實時堆實現,但它們並沒有被廣泛使用。一般規則是在初始化之後避免在硬實時系統中進行任何動態分配或釋放。

3

我的印象是,在嵌入式系統上,我確切地知道多少內存可用,我被允許使用的它究竟是100%;沒有必要爲其他(同時運行的)程序留下一點空間,但也沒有可用的虛擬內存給我101%。所以對於一個隊列,我可以很容易地計算出我有空間(比如說)981條記錄;所以我爲這些記錄創建了一個數組,並且如果我需要第982條記錄,我會被徹底刪除,並且必須找到一種正常失敗的方式。

+0

我的大部分嵌入式工作都是在政府職位上,那裏有一個例行的要求,要留下50%備用於未來的升級。商業世界不這樣做嗎? – 2013-11-25 14:29:56

+0

T.E.D.這是我從你那裏學到的明智建議 – bazz 2015-03-25 14:14:58

0

嵌入式系統上的動態數據結構有點像C++中的指針。指針(在C++中)是邪惡的。但有時他們是唯一的選擇;有時他們是較小的邪惡;有時可以完全避免它們。如果是使用它們的一個很好的理由,那麼可以有「好」的方法和「壞」的方法來做到這一點。

靜態分配變量和數組快得多到分配和釋放,並且能更快地訪問,比動態分配的數據。見this answer

動態分配(我的意思是malloc() ed或類似)數據還需要空間開銷跟蹤分配。至少每個分配有幾個字節 - 這個空間在嵌入式系統上非常有價值!

內存泄漏是大規模嵌入式系統的問題,它有時可能會運行多年。從這個角度來看,避免動態分配是謹慎的。

嵌入式設備通常具有相當可靠的規格。你知道傳輸速率是什麼,你知道你可以以多快的速度處理信息,等等。在您的示例中,解決方案是使用固定大小的緩衝區作爲circular queue。使緩衝區足夠大,以處理你的設備需要處理的能力(也許還有一點點)。如果數據太多,可能是由於故障或干擾造成的,所以沒有太多的意義,並試圖使用所有的數據。

4

這取決於如在過去的4年拓寬了我的看法「嵌入式」的意思。

傳統上,嵌入式設備上有微控制器,通常沒有操作系統。沒有受保護的內存,並且是單線程的。你必須非常小心,因爲當你只有32KB的可用內存時,它很容易耗盡。所以一般來說,我們會用固定大小的緩衝區編寫我們的代碼,並且從不使用malloc或者如果每次都使用它 - 非常謹慎。

在我們看到在過去幾年什麼本質上是單芯片的PC或者微電路板,他們很容易成爲我們的老奔騰電腦一樣強大。內存價格現在非常便宜,而且非常小,以至於內存限制與它們無關。他們還經常運行嵌入式Linux或wince,所以現在我們可以更加寬鬆地使用動態內存。

由於這是能夠使用更廣泛的語言,包括Java,C++,許多腳本語言和其他語言,提供緩衝區溢出保護和異常處理以及其他更高級別的語言。所以真的,那些老問題不像以前那樣。

我懷疑所有這些新的可用硬件出現了一系列新問題。

+0

32 KB RAM!你很幸運。我有1 KB的RAM(我們所有26)至極,我必須分享他的CPU堆棧 – 2009-11-12 23:20:08

0

我不知道Atmel MEGA169,但我猜想MEGA168與169有關,只有1024字節的 SRAM。它也只有16k的程序ROM,與現代計算機相比相對較慢。所以它在內存,程序大小和速度方面受到限制。

在我使用AVR彙編程序編程的經驗中,需要儘可能多地將功能塞入PIC中。使用動態數據結構所需的額外開銷(額外的內存使用,從SRAM拉取和推送數據所需的額外指令,跟蹤哪個動態變量駐留在哪裏,當變量處於'之間'時,移動內存塊'。 ..)只是不能證明優點。

所以,即使編譯器實現它,我會堅持使用靜態數據結構來提高性能。

+0

PIC? OP在詢問AVR。 – iter 2010-03-02 04:45:20

+0

我也在談論AVR。我的錯。 – thomaspaulb 2010-03-08 14:42:10

2

在嵌入式環境中,動態內存本身並沒有什麼問題,但通常它在嵌入式環境中並不會給你帶來太多的收益。

在我看來,它是一個非常好的主意使用環緩衝區(這是一個非常通用的I/O驅動程序等數據結構)。這樣,如果由於某種原因無法爲您的隊列提供服務,內存使用情況仍然是確定性的。

使用一些宏可以在編譯時分配可變大小的結構。

例如 -

//we exploit the fact that C doesn't check array indices to allow dynamic alloc of this struct 
    typedef struct ring_buf_t { 
     int element_sz, 
      buffer_sz, 
      head, 
      tail; 
     char data[0]; 
    } ring_buf_t; 

    #define RING_BUF_ALLOC_SZ(element_sz,n_elements) (sizeof (ring_buf_t) + \ 
                 (element_sz) * (n_elements)) 

    char backing_buf[RING_BUF_ALLOC_SZ (sizeof(type_to_buffer), 16)]; 

    //ring_buf_init() casts backing buf ring_buf_t and initialises members... 
    ring_buf_t *ring_buffer = ring_buf_init (element_sz, n_elemements, backing_buf); 

;

這種模式是一個動態可調整大小的緩衝區,具有保證內存使用的功能。當然,其他類型的數據結構(列表,隊列等)也可以用相同的方式實現。