【KEIL·单片机·扫盲贴】关于ARM单片机程序内存使用情况的细致讨论。
接觸了兩年多時(shí)間的單片機(jī)編程本人對(duì)關(guān)于單片機(jī)程序內(nèi)存如何耗費(fèi)的問(wèn)題一直懵懵懂懂,直到在近日看到某篇有關(guān)于MDK?MAP文件介紹的帖子后才有種醍醐灌頂?shù)母杏X(jué),這里我將分享在此之上的觀點(diǎn)與見(jiàn)解以供大家討論學(xué)習(xí)。
大家都知道ARM單片機(jī)的內(nèi)部存儲(chǔ)空間極其匱乏無(wú)論是從Flash還是RAM上,每每給單片機(jī)機(jī)編程都有一種惜字如金的感覺(jué),工程師們一般會(huì)在容量有限的情況下規(guī)范其編程習(xí)慣簡(jiǎn)化代碼避免冗余,那么首先我們?nèi)绾沃赖某绦蛳螺d到單片機(jī)上到底占用了多少Flash程序運(yùn)行又會(huì)使用多少RAM?
首先上一張圖:
該圖是KEIL編譯某個(gè)單片機(jī)程序后生成的構(gòu)建信息,這里我們只關(guān)注其中的Program Size信息。
Program Size其意義是編譯后生成的代碼大小單位是字節(jié),Program Size的大小有四大決定因素:Code,RO-data,RW-data,ZI-data 。
?
Code :意義是代碼指令占用的空間;
RO-data? :是Read Only?Data的縮寫(xiě),意義是只讀常量占用的空間。如const型常量,常量字符串等等;
RW-data :是Read Write?Data的縮寫(xiě),意義是可讀可寫(xiě)的已初始化 了的變量占用的空間。如全局變量,靜態(tài)變量等等;
ZI-data :是Zero?Initialize??Data的縮寫(xiě),意義是以0初始化的變量。如未初始化賦值的全局變量,靜態(tài)變量等等;
綜上來(lái)說(shuō)?燒寫(xiě)的時(shí)候是FLASH中的被占用的空間大小為:Code?+?RO?Data?+?RW?Data,而程序運(yùn)行的時(shí)候數(shù)據(jù)使用到的RAM的空間大小為:RW?Data?+?ZI?Data。
?
Why?
FLASH中的被占用的空間很好理解,就是等于代碼指令+只讀數(shù)據(jù)的值+已初始化變量的值。那么運(yùn)行時(shí)數(shù)據(jù)占用RAM空間大小==RW?Data?+?ZI?Data又作何理解?
我們都知道,在代碼運(yùn)行機(jī)制上單片機(jī)不同于PC,單片機(jī)的程序通常是在FLASH中直接取指執(zhí)行,而PC是先把程序拷貝到RAM中再取指執(zhí)行。
由上說(shuō)明單片機(jī)的RAM中至少不會(huì)存在Code拷貝(除非使用了特殊方法強(qiáng)行使程序拷貝到了RAM中執(zhí)行,本貼不討論此情況),
其次,單片機(jī)RAM中也不會(huì)存在RO-data拷貝,因?yàn)镽O-data是只讀數(shù)據(jù),為了節(jié)省RAM空間,這種數(shù)據(jù)在執(zhí)行時(shí)直接從FLASH中取出使用,無(wú)需再?gòu)?fù)制到RAM。
那么剩下的?RW?Data?+?ZI?Data由于是可讀可寫(xiě)的數(shù)據(jù),為了能夠供程序運(yùn)行時(shí)正常讀寫(xiě),于是就會(huì)被放在單片機(jī)的RAM中(單片機(jī)的FLASH區(qū)不能被程序改寫(xiě))。
有人可能會(huì)問(wèn)RW-data?與ZI-data都是指的全局變量或者靜態(tài)變量,那么程序中的局部變量去了哪兒?這里就要向大家澄清一個(gè)事實(shí),在C或C++中全局變量或?靜態(tài)變量在RAM中都有一個(gè)特定地址(存在于靜態(tài)區(qū)),而局部變量卻沒(méi)有特定的地址
因?yàn)榫植孔兞看嬖谟跅V?#xff08;存在于堆棧區(qū)),當(dāng)函數(shù)入棧時(shí)系統(tǒng)就會(huì)在棧頂之上開(kāi)辟一段內(nèi)存供給局部變量使用,當(dāng)函數(shù)出棧時(shí)該內(nèi)存就會(huì)被釋放掉。
?
那么單片機(jī)在程序運(yùn)行時(shí)RAM的使用量就等于RW?Data?+?ZI?Data了嗎,還有沒(méi)有其他因素會(huì)導(dǎo)致RAM占用變化?
玩過(guò)PC的都知道,一個(gè)程序在運(yùn)行時(shí)它在內(nèi)存中的占用情況是會(huì)隨時(shí)改變的,這其中可能有壓棧入棧和堆塊的申請(qǐng)與釋放等事件發(fā)生,那么在單片機(jī)里難道就沒(méi)有這樣的過(guò)程了嗎?答案都是否定的。
單片機(jī)的RAM中也有堆棧區(qū),那么程序運(yùn)行時(shí)RAM的使用量就不會(huì)再等于RW?Data?+?ZI?Data了,因?yàn)槌绦虻亩褩^(qū)也是一段具體的內(nèi)存,那么堆棧區(qū)的內(nèi)存占用又有多大?
堆棧區(qū)大小的查詢(xún)方法,這里以STM32F1系列作為介紹,以航跡雲(yún)STF1驅(qū)動(dòng)集合庫(kù)中的startup_stm32f10x_hd.s啟動(dòng)文件為例:
(看不清圖片的朋友們,請(qǐng)右鍵查看圖片)
圖中有個(gè)Stack_Size(棧大小)與Heap_Size(堆大小)定義,這兩十六進(jìn)制的數(shù)值之和就是你的單片機(jī)運(yùn)行時(shí)RAM中的堆棧字節(jié)大小,其他單片機(jī)平臺(tái)的堆棧大小查詢(xún)方法請(qǐng)自行百度。
以上可以得出,一個(gè)arm架構(gòu)的單片機(jī)的程序在運(yùn)行時(shí)將會(huì)占用到的RAM空間等于 RW?Data?+?ZI?Data +?Stack_Size + Heap_Size;
?
那么在程序運(yùn)行時(shí)還有沒(méi)有其他因素會(huì)導(dǎo)致RAM被使用的空間發(fā)生變化?
在回答這個(gè)問(wèn)題之前,我們先來(lái)討論何為 “在編譯時(shí)編譯器會(huì)為一個(gè)變量分配一段內(nèi)存” ?玩過(guò)匯編的都知道編譯器并不會(huì)給變量一個(gè)內(nèi)存,?而是編譯器在內(nèi)存中為變量指定了一個(gè)地址而已,然后讓其他變量不會(huì)重復(fù)指向該地址,在編譯時(shí)編譯器會(huì)把變量名由地址替換掉,這樣就達(dá)到了貌似"編譯器給變量分配了內(nèi)存"?的效果。
因?yàn)榫幾g器為每個(gè)變量分配地址且不會(huì)讓該地址被占用,由此得知RW?Data?+?ZI?Data這兩塊數(shù)據(jù)在被分配好內(nèi)存之后會(huì)一直處于無(wú)法被回收的狀態(tài),根據(jù)認(rèn)知科學(xué)一一無(wú)法回收==占用,所以RAM中的RW?Data?+?ZI?Data區(qū)就會(huì)一直處于占用狀態(tài),如果沒(méi)有新的程序燒錄進(jìn)來(lái)RW?Data?+?ZI?Data區(qū)占用的空間是不會(huì)變的。
那么堆棧區(qū)就更不用說(shuō)了,堆棧區(qū)的大小是由單片機(jī)的啟動(dòng)文件中Stack_Size?與?Heap_Size確定的,函數(shù)入棧出棧變的只是堆棧區(qū)內(nèi)的數(shù)據(jù)而不是變化堆棧區(qū)大小(?注:如果函數(shù)入棧的數(shù)量超出了堆棧區(qū)的大小限制則為爆棧),如果沒(méi)有新的程序燒錄進(jìn)來(lái)Stack_Size?+ Heap_Size區(qū)占用的空間也是不會(huì)變的。
?
結(jié)論:ARM單片機(jī)中的FLASH的占用量取決于Code?+?RO?Data?+?RW?Data,程序運(yùn)行時(shí)RAM的占用量取決于?RW?Data?+?ZI?Data +?Stack_Size + Heap_Size且在程序運(yùn)行過(guò)程中該占用量幾乎不變;?
?
?
這是我的第一篇博客,以上皆為個(gè)人愚解,如有不周歡迎斧正。
?2017/9/11 航跡雲(yún)
轉(zhuǎn)載于:https://www.cnblogs.com/Contrail/p/7502066.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專(zhuān)家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的【KEIL·单片机·扫盲贴】关于ARM单片机程序内存使用情况的细致讨论。的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java web学习笔记-jsp篇
- 下一篇: 总结JS常用方法