【KEIL·單片機·掃盲貼】關於ARM單片機程序內存使用情況的細致討論。


接觸了兩年多時間的單片機編程本人對關於單片機程序內存如何耗費的問題一直懵懵懂懂,直到在近日看到某篇有關於MDK MAP文件介紹的帖子后才有種醍醐灌頂的感覺,這里我將分享在此之上的觀點與見解以供大家討論學習。

大家都知道ARM單片機的內部存儲空間極其匱乏無論是從Flash還是RAM上,每每給單片機機編程都有一種惜字如金的感覺,工程師們一般會在容量有限的情況下規范其編程習慣簡化代碼避免冗余,那么首先我們如何知道的程序下載到單片機上到底占用了多少Flash程序運行又會使用多少RAM?

首先上一張圖:

該圖是KEIL編譯某個單片機程序后生成的構建信息,這里我們只關注其中的Program Size信息。

Program Size其意義是編譯后生成的代碼大小單位是字節,Program Size的大小有四大決定因素:Code,RO-data,RW-data,ZI-data 。

 

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?

FLASH中的被占用的空間很好理解,就是等於代碼指令+只讀數據的值+已初始化變量的值。那么運行時數據占用RAM空間大小==RW Data + ZI Data又作何理解?

我們都知道,在代碼運行機制上單片機不同於PC,單片機的程序通常是在FLASH中直接取指執行,而PC是先把程序拷貝到RAM中再取指執行。

由上說明單片機的RAM中至少不會存在Code拷貝(除非使用了特殊方法強行使程序拷貝到了RAM中執行,本貼不討論此情況),

其次,單片機RAM中也不會存在RO-data拷貝,因為RO-data是只讀數據,為了節省RAM空間,這種數據在執行時直接從FLASH中取出使用,無需再復制到RAM。

那么剩下的 RW Data + ZI Data由於是可讀可寫的數據,為了能夠供程序運行時正常讀寫,於是就會被放在單片機的RAM中(單片機的FLASH區不能被程序改寫)。

有人可能會問RW-data 與ZI-data都是指的全局變量或者靜態變量,那么程序中的局部變量去了哪兒?這里就要向大家澄清一個事實,在C或C++中全局變量或 靜態變量在RAM中都有一個特定地址(存在於靜態區),而局部變量卻沒有特定的地址

因為局部變量存在於棧中(存在於堆棧區),當函數入棧時系統就會在棧頂之上開辟一段內存供給局部變量使用,當函數出棧時該內存就會被釋放掉。

 

那么單片機在程序運行時RAM的使用量就等於RW Data + ZI Data了嗎,還有沒有其他因素會導致RAM占用變化?

玩過PC的都知道,一個程序在運行時它在內存中的占用情況是會隨時改變的,這其中可能有壓棧入棧和堆塊的申請與釋放等事件發生,那么在單片機里難道就沒有這樣的過程了嗎?答案都是否定的。

單片機的RAM中也有堆棧區,那么程序運行時RAM的使用量就不會再等於RW Data + ZI Data了,因為程序的堆棧區也是一段具體的內存,那么堆棧區的內存占用又有多大?

堆棧區大小的查詢方法,這里以STM32F1系列作為介紹,以航跡雲STF1驅動集合庫中的startup_stm32f10x_hd.s啟動文件為例:

(看不清圖片的朋友們,請右鍵查看圖片)

圖中有個Stack_Size(棧大小)與Heap_Size(堆大小)定義,這兩十六進制的數值之和就是你的單片機運行時RAM中的堆棧字節大小,其他單片機平台的堆棧大小查詢方法請自行百度。

以上可以得出,一個arm架構的單片機的程序在運行時將會占用到的RAM空間等於 RW Data + ZI Data + Stack_Size + Heap_Size;

 

那么在程序運行時還有沒有其他因素會導致RAM被使用的空間發生變化?

在回答這個問題之前,我們先來討論何為 “在編譯時編譯器會為一個變量分配一段內存” ?玩過匯編的都知道編譯器並不會給變量一個內存, 而是編譯器在內存中為變量指定了一個地址而已,然后讓其他變量不會重復指向該地址,在編譯時編譯器會把變量名由地址替換掉,這樣就達到了貌似"編譯器給變量分配了內存" 的效果。

因為編譯器為每個變量分配地址且不會讓該地址被占用,由此得知RW Data + ZI Data這兩塊數據在被分配好內存之后會一直處於無法被回收的狀態,根據認知科學一一無法回收==占用,所以RAM中的RW Data + ZI Data區就會一直處於占用狀態,如果沒有新的程序燒錄進來RW Data + ZI Data區占用的空間是不會變的。

那么堆棧區就更不用說了,堆棧區的大小是由單片機的啟動文件中Stack_Size 與 Heap_Size確定的,函數入棧出棧變的只是堆棧區內的數據而不是變化堆棧區大小( 注:如果函數入棧的數量超出了堆棧區的大小限制則為爆棧),如果沒有新的程序燒錄進來Stack_Size + Heap_Size區占用的空間也是不會變的。

 

結論:ARM單片機中的FLASH的占用量取決於Code + RO Data + RW Data,程序運行時RAM的占用量取決於 RW Data + ZI Data + Stack_Size + Heap_Size且在程序運行過程中該占用量幾乎不變; 

 

 

這是我的第一篇博客,以上皆為個人愚解,如有不周歡迎斧正。

 2017/9/11  航跡雲 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM