更新曆史
20220318
- 首次編輯,簡述 keil 工程生成的代碼大小,以及存放的空間位置;
文章目錄
- 引言
- 生成資料區分
-
- 各資料含義
-
- 為什麼 RW 資料有兩份?
- 如何縮減空間
-
- 閃存空間
- RAM 空間
-
- FreeRTOS 堆空間簡述
- 參考資料
引言
這篇文章介紹了 keil 工程生成代碼的各中 data 的介紹,以及在位址空間中的存放差異。
依舊是【固件防複制系列】的衍射知識總結,在真正讨論程式加載以及堆棧的配置設定及使用問題前,先以 keil 為實踐 IDE 對象來簡單描述下代碼生成後,各種資料的放置空間,以及若存在空間不足情況下,代碼的簡單體積縮減。
生成資料區分
各資料含義
圖1 keil 編譯資訊截圖
這裡我們可以看到:
這裡的數值,機關均為位元組 Byte。
先分别來說下,各部分的含義:
-
Code: 代碼大小
這個很容易了解,也是我們程式最主要的部分;90512 位元組
-
RO-data: Read Only data, 隻讀性質的資料
如字元串,const 資料;4184 位元組
-
RW-data: Read Write data, 可讀可寫性質的資料
已初始化的全局變量;820 位元組
-
ZI-data: Zero Initialized, 初始值為 0 的資料
未初始化的全局變量;44140 位元組
關于其放置位置,也是根據 MCU 存儲媒體的性質以及本身的操作類型來決定的,我們知道 MCU 的閃存或 Flash 空間其屬于 ROM 存儲器,适合存放隻讀或初始化值非 0 的資料,而 RAM 則适合存放反複修改的資料類型。
(RW-data 會先配置設定到閃存,但是由于其 RW 的性質,會在 RAM 中進行拷貝。)
則會有下面的配置設定:
Flash_occupied = Code + RO-data + RW-data = 95516 Bytes = 93 MB
RAM_occupied = RW-data + ZI-data = 44960 Bytes = 43 MB
為什麼 RW 資料有兩份?
RW 我們知道是初始化且非 0 的全局變量,也就是說相當于我們看書,看到了某個進度,需要下次再看,這裡就需要記錄一下進度。
由于 RAM 是掉電即失,則不會也不适合将這個進度的記錄放到 RAM 中(程式的放置或者映射位置是編譯器工具鍊進行設定的,而資料本身的讀寫性質是工程師進行編碼确定的,映射放置時隻看本身的讀寫性質),而又由于程式運作中,會對其進行讀寫(産品電源周期内的運作态),是以需要一塊掉電不易失的存儲空間來存儲,這就會将其放置到了閃存及 Flash 空間。
相應的, ZI-data 放在了 RAM 區,因為其是未初始化或者初始化值為 0 的變量,則不用占用閃存空間(相當于,知道是新書,也不用記錄這次看到哪了,拿起來看就完了),運作中進行預設初始化為 0 .
注:關于加載的知識,詳細請見《程式員的自我修養》,具體版本請見參考資料章節。
如何縮減空間
在嵌入式開發領域中,嵌入式資源是寶貴的,不免會遇到代碼體積過大或需要進行優化的情況,單單從代碼體積來看,可以如何縮小占用空間。
想要有的放矢的縮減尺寸,需要了解哪些資料屬于 RO, RW 和 ZI。
閃存空間
- 優化代碼文法的使用;如替換 while(1) 為 for( ; ; ),這樣彙編語句會減少,且不占用寄存器,沒有判斷和跳轉,空間和時間上都具有優勢:
while (1);
// while(1) 編譯後
mov eax,1
test eax,eax
je foo+23h
jmp foo+18h
for(;;);
// 編譯後
jmp foo+23h
- 結構體成員之間的排列問題;
- 不需要的字元串或 const 常量的删減;(RO-data區)
- 。。。
RAM 空間
這裡的 RAM 一定程度上可以了解為運作時用的空間,涉及到動态建立、修改和通路的資料及資料結構都會放置于這裡,比如一些任務控制塊、堆棧等。
簡化這部分的使用大小:
- 避免棧空間的大量使用,會導緻記憶體溢出;
- 簡化函數調用;
- 避免一些不用但是依舊聲明的數組等;
- 。。。
如我在代碼中注釋掉了僵屍代碼,一個在源檔案中申明的全局數組(外部源檔案沒有引用):
我們可以看到,這個資料為 64 長的 32 位元組元素長度的數組,計算下來就需要 256 位元組長度的 RAM 空間,這裡注釋掉後,再次編譯:
圖2 keil 編譯資訊截圖(删除備援代碼後)
這裡我們對比圖1,發現 ZI-data 的大小減少了 44140-43884=256 Byte,也就是我們剛才注釋掉的數組大小。
注:這裡隻是示範了一個很簡單的政策,當生成代碼大小與預期不一緻,有些許出入也是很正常的。
FreeRTOS 堆空間簡述
這裡簡單提一下,如果包含了作業系統的話,比我們産品中使用的是 FreeRTOS,其是在 RAM 區申請了一個較大空間的數組,也就是連續存儲空間以作為其本身資源的消耗及管理,這部分是計算在 ZI-data 空間内的,具體大小檢視宏定義,比如 v10.0.1 版本的 FreeRTOS 系統堆空間為 15M:
圖3 FreeRTOS 堆空間大小宏定義
圖4 FreeRTOS 不同記憶體管理政策下的空間申請
結合圖 3、4 我們可知,不同的記憶體管理政策,都是在 15MB 堆空間大小的前提下,至于不同的記憶體管理政策具體有什麼不同,請參考 FreeRTOS 官網手冊: Memory Management; 根據自身開發需求來標明政策。
參考資料
- stackoverflow - ROM and RAM in ARM;
- Arm Cortex-M4 Processor Technical Reference Manual;
- FreeRTOS Developer Docs;
- 《程式員的自我修養 - 連結、轉載與庫》,俞甲子 石凡 潘愛民 著,中國工信出版社;