1. 程式人生 > >在KEIL下檢視微控制器程式設計記憶體使用情況

在KEIL下檢視微控制器程式設計記憶體使用情況

截至到目前為止,本人接觸微控制器也有將近一年的時間。這一年以來也接觸過了很具代表性的微控制器,比如51、HT32、STM32等等。但是呢對於微控制器的記憶體一直不瞭解,一直到現在,在一次微控制器程式設計時我用到了malloc函式為指標分配記憶體空間。不知道為什麼記憶體一直分配不成功。

所以這才去瞭解微控制器的記憶體。下圖是KELI編譯成功後的輸出資訊。

 

在這裡,我們先只關心Program Size這一行:

Code:程式碼指令佔用的空間;

RO-data:Read Only Data的縮寫。它的意義是隻讀常量佔用的空間,比如const型常量、字串常量等等;

           RW-data:

Read Write Data的縮寫。它的意義是可讀可寫並且已初始化了的遍歷所佔用的空間,比如全域性變數,靜 態變數等等;

           ZI-data:Zero Initialize Data的縮寫。它的意義是以0初始化的變數,比如未初始化賦值的全域性變數、靜態變數等等;

而對微控制器燒寫程式時,FLASH被佔用的空間大小為:Code + RO Data + RW Data,但是程式執行時使用到的RAM空間大小為:RW Data + ZI Data。

 

Why?

FALSH中被佔用的空間 == 程式碼指令  + 只讀資料值 + 已初始化變數的值。那麼為什麼程式執行時佔用RAM空間大小 == RW Data + ZI Data呢?

我們都知道,在程式碼執行機制上微控制器不同於PC,微控制器的程式通常是在FALSH中直接取指執行,而PC是先把程式拷貝到RAM中再取指執行。因此微控制器的RAM中不會存在Code拷貝(除非使用特殊方法強行使程式拷貝到了RAM中執行)。另外微控制器RAM中也不會存在RO-data拷貝,因為RO-data是隻讀資料,為了節省RAM空間,這種資料在執行時直接從FLASH中取出使用,無需再複製到RAM。又由於RW Data和ZI Data是可讀可寫資料,為了供程式執行時正常讀寫,於是就會被放在微控制器的RAM中(微控制器的FLASH區不能被程式改寫)

那麼對於區域性變數來說(RW Data和ZI data都是指的是全域性變數或者靜態變數),在C語言中全域性變數和靜態變數在RAM中都有一個特定的地址(存於靜態區),而區域性變數沒有特定的地址。因此區域性變數會被存放於堆疊中,當函式入棧時系統就會在棧頂開闢一段記憶體供區域性變數使用,函數出棧時該記憶體就會被釋放掉(靜態區域性變數除外)。

那麼微控制器程式在執行時RAM的使用量就等於RW Data + ZI Data了嗎?還有沒有其他因素會導致RAM佔用變化?

玩過PC的都知道,一個程式在執行時它在記憶體中的佔用情況是會隨時改變的,這其中可能有壓棧入棧和堆塊的申請與釋放等事件發生,那麼在微控制器裡難道就沒有這樣的過程了嗎?

其實微控制器的RAM中也有堆疊區,因此程式執行時RAM的使用量就不會再等於RW Data + ZI Data了。(STM32的堆疊是存放於SRAM中的)而是等於 RW Data + ZI Data + Stack_Size + Heap_Size;

另外編譯器並不會給變數一個記憶體,而是在記憶體中為變數指定一個地址,然後讓其他變數不會重複指向該地址。在編譯時編譯器會把變數名用地址替換掉,這樣也就達到了“編譯器給變數分配了記憶體”的效果。那麼,因為編譯器為每個變數分配地址且不會讓該地址被佔用,由此可知RW Data 和 ZI Data這兩塊資料在被分配好記憶體之後一直會處於無法被回收的狀態。因此如果沒有新的程式燒錄至微控制器,RW Data + ZI Data區佔用的空間是不會變的。

而對於堆疊區,堆疊區的大小是由啟動檔案確定的。函式入棧、出棧的過程變化的只是區內的資料而不是堆疊區的大小(入棧數量超過了棧區的大小限制則為爆棧)。因此沒有新的程式燒錄至微控制器,堆疊區的大小也不會改變。

結論:ARM微控制器中的FLASH佔有量 == Code + RO Data + RW Data,程式執行時RAM的佔有量 == RW Data + ZI Data + Stack_Size + Heap_Size