在許多嵌入式專案中,RAM 往往不是工程師一開始最擔心的資源。早期原型通常跑在評估板上都很順,測試用韌體隨著需求慢慢長大,記憶體用量看起來也「還算夠用」。

但現實終究會到來。

新增一個功能、診斷機制擴充、安全性更新引入新的 buffer,突然之間,RAM 用量不再只是安全邊際,而是直接成為開發瓶頸。一旦 RAM 成為限制條件,影響往往不只停留在軟體層面。

在嵌入式系統中,RAM 不夠用通常代表必須重新設計硬體、改選更大容量的 MCU,或是在專案後期重新驗證新的型號。

這類變動會一路影響到整個組織,從採購、認證、製造到長期供應規劃。結果造成 BOM 成本上升、時程延誤,整體風險也隨之增加。

這也是為什麼 RAM 最佳化不只是技術問題,而是策略層級的考量。

與 Flash 不同,在低階與中階 MCU 上,RAM 的容量並不是線性增加的。一點點 RAM 需求的成長,往往就會被迫帶來:

  • 升級到更高階的 MCU 系列
  • 改用不同的封裝或腳位配置
  • 額外的功耗增加
  • 重新進行驗證與確認(qualification / validation)

對於長生命週期產品、感測節點、系統控制器或工業型閘道器而言,這類變更的成本往往非常高。

而讓這個問題在今天變得更嚴峻的,是 RAM 的價格與供應狀況,越來越受到嵌入式產業以外的全球市場因素影響。

來自 AI 系統與超大型資料中心的需求暴增,已經徹底改變了記憶體市場。AI 模型的訓練與部署需要大量高頻寬記憶體,迫使製造商優先投入高毛利產品,並重新分配產能。

因此:

  • 一般商品型記憶體的製造吸引力下降
  • 整體市場的供應配額趨於緊縮
  • 價格壓力影響整個記憶體生態系

需要特別區分的是,這些變化對不同嵌入式架構的影響並不相同。

以 MCU 為基礎的設計,多半使用晶片內建 RAM,其容量在晶片設計階段就已固定,較不直接受到外部記憶體市場影響;相對地,以 MPU 為核心的系統則仰賴外接 DDR 或 LPDDR,會更直接與其他商品型記憶體產品競爭相同的製造產能。

即使嵌入式系統本身不使用 AI 等級的記憶體,也無法完全置身事外。

對於高出貨量產品來說,即便只是外部記憶體成本的小幅上漲,或供應可得性下降,都可能對 BOM、採購策略與產品長期可行性造成顯著影響。

即便 MCU 受影響較間接,長期的記憶體生態系壓力,仍會逐步反映在價格、交期與架構選擇上。

主動管理 RAM 使用量的團隊,得到的價值遠不只是多出幾個 byte,而是設計彈性。

他們可以在不更動硬體的情況下,承接功能成長、安全性更新與法規合規需求。

在實際專案中,最常見的情況之一,就是全域變數與靜態變數不斷累積。一開始的出發點通常是好的:共用狀態、使用方便、存取速度快,但久而久之,它們就成了 RAM 裡的長期住戶。

由於全域與靜態物件在系統整個生命週期中都存在,它們會:

  • 在系統啟動時就占用可用記憶體
  • 增加初始化的負擔
  • 掩蓋實際的執行期記憶體需求

在實務上,將變數從全域範圍移到函式內,通常不會帶來效能損失,卻能在函式結束後立即釋放 RAM。

透過 IAR 的 linker map file,這些長生命週期的配置非常容易被找出來。工程師不必再猜 RAM 用到哪裡,而是能清楚看到是哪個模組、哪個符號在消耗記憶體,並判斷是否真的需要永久配置。

在許多嵌入式系統中,記憶體浪費往往不是來自一個大錯誤,而是成千上萬個小選擇累積而成。

在只需要 uint8_t 的地方使用 int,就是經典例子。單看一個變數差異不大,但放在陣列、結構、佇列與 stack 裡,很快就會累積成可觀的浪費。

uint8_t status;

uint16_t measurement;

選擇「最小且正確」的型別,可以:

  • 降低 RAM 使用量
  • 改善快取行為
  • 往往同時提升效能並降低功耗

這在感測器密集的系統中特別重要,因為資料結構會被大量複製,任何低效率都會隨著系統複雜度被放大。

即使是寫得很乾淨的程式碼,也可能因為結構 padding 與對齊(alignment)而浪費 RAM。

重新排列結構成員,並用 bitfield 來表示旗標,往往能大幅降低記憶體使用量,特別是在結構被大量實例化或放入陣列時。

typedef struct

{

   uint16_t value;

   uint8_t state;

   uint8_t flags : 3;

} DeviceStatus;

這些最佳化在執行期幾乎感覺不到,但在 linker map file 中非常明顯,最終也會反映在 BOM 成本上。

一個出乎意料卻很常見的 RAM 浪費來源,是啟動時被複製進 RAM 的常數資料。字串、查表資料與設定資料,如果沒有妥善處理,很容易在不知不覺中吃掉大量記憶體。

透過一致性地使用 const,開發者可以確保資料留在 Flash 中,而不是佔用 RAM:

const uint16_t calibrationTable[128] = { /* Flash-resident */ };

在 IAR 工具鏈中,資料放置位置是明確且可預期的,這在受法規約束或安全關鍵的應用場景中特別重要,因為記憶體行為必須清楚被理解並文件化。

動態記憶體配置之所以吸引人,是因為看起來很彈性;但在嵌入式系統中,這份彈性往往代價不低:

  • 長時間運作後產生記憶體碎裂
  • 非決定性的配置失敗
  • 難以除錯的 runtime 當機問題

對於需要連續運作數月甚至數年的系統來說,動態配置通常不值得承擔這些風險。

因此,許多團隊會用以下方式取代 heap:

  • 靜態 buffer
  • 固定大小的記憶體池
  • 應用程式專用的配置器

這樣做的結果是記憶體行為可預期、測試更單純、系統可靠度提升,特別適合 RAM 邊際本來就很吃緊的情況。

Stack overflow 是最難診斷的問題之一,往往只在特定條件下才會發生,例如排程與時序交錯造成的特殊情境。

大型區域變數、過深的呼叫鏈,或遞迴呼叫,都可能快速耗盡 stack,在 RTOS 系統中特別容易發生。

透過 IAR 的 stack 分析工具,開發者可以:

  • 估算最壞情況下的 stack 使用量
  • 合理配置各 task 的 stack 大小
  • 避免在專案後期才出現、又難以重現的問題

編譯器的 size 最佳化(-Os)通常被認為只是省 Flash,但它其實也會直接影響 RAM 使用量:

  • 減少暫存變數
  • 降低 stack 壓力
  • 減少需要初始化的資料

搭配 section garbage collection 與定期檢視 linker map file,可以避免軟體隨著演進,記憶體用量在不知不覺中膨脹。

RTOS kernel 功能強大,但預設設定通常偏保守。過大的 stack、未使用的功能與通用化設定,都可能吃掉大量 RAM。

逐一調整 RTOS 的設定檔與各個 task,往往就能釋放出足夠的記憶體,甚至完全避免硬體升級。

RAM 最佳化真正的價值,不在於省下多少 byte,而在於多了多少選項。

主動管理 RAM 的團隊可以:

  • 更長時間地維持在較小容量的 MCU
  • 避免專案後期的硬體變更
  • 降低供應鏈風險
  • 在不犧牲功能的情況下降低 BOM 成本

透過 IAR 嵌入式開發平台,RAM 使用量變得可視、可預測、可管理,讓記憶體最佳化不再只是救火,而是一套可重複執行的工程流程。

在嵌入式系統中,每一個 RAM byte 都有成本。有時體現在矽晶片上,有時則反映在時程、認證或供應鏈上。

在全球記憶體需求越來越被 AI 與資料中心主導的環境下,即使是「純」嵌入式系統,也無法不感受到這股壓力。

將 RAM 視為一級設計限制,並搭配合適的工具加以管理,嵌入式團隊就能打造出不僅效率高、也具備經濟韌性的系統。

歡迎了解 IAR 如何協助最佳化你的嵌入式開發專案。透過互動式展示快速認識 IAR 平台,並進一步探索其進階功能與解決方案。

本文由IAR提供

延伸閱讀⎟