STM32 記憶體分配解析及變數的儲存位置

2022-09-14 07:39:10 字數 2899 閱讀 3498

原文

記憶體對映

在一些桌面程式中,整個記憶體對映是通過虛擬記憶體來進行管理的,使用一種稱為記憶體管理單元(mmu)的硬體結構來將程式的記憶體對映到物理ram。在對於 ram 緊缺的嵌入式系統中,是缺少 mmu 記憶體管理單元的。因此在一些嵌入式系統中,比如常用的 stm32 來講,記憶體對映被劃分為快閃儲存器段(也被稱為flash,用於儲存**和唯讀資料)和ram段,用於儲存讀寫資料。

從圖中我們可以看到 ram 位址是從 0x2000 0000 開始的,flash位址是從 0x0800 0000 開始的,筆者將在下文中著重對這兩部分進行剖析。

flash

**和資料是存放在 flash 中的,下面是將 flash 內部進行細分之後的一張圖,圖中標明了**段,資料段以及常量在 flash 中的位置。

如上圖所示,flash 又可以細分為這麼幾個部分,分別是文字段 (text),其中文字段中又包含可執行** (executable code)和常量 (literal value),在文字段之後就是唯讀資料區域 (read only data),當然並不是所有架構的微控制器都滿足這樣乙個排布規律,這裡只針對arm cortex m3 系列,唯讀資料段後面接著的就是資料複製段 (copy of data section),第一次遇到這個概念的朋友看到資料複製可能會有所疑惑,其實這個段充當的作用是存放程式中初始化為非 0 值的全域性變數的初始值,之所以要將初始值存放到這裡,是因為全域性變數是存放在 ram 上的,ram 上的值掉電便丟失,每次上電後這些變數是要進行重新賦值的,而重新賦的值就存放在這裡。那為什麼不存放初始化為 0 的全域性變數初始值呢,原因也很簡單,既然是初始化為 0,那麼在上電後統一對存放初始化為 0 的全域性變數的那塊區域清0就好了。下面舉乙個例子分析各個變數在上述中的儲存位置:

#include const

int read_only_variable = 2000

;int data = 500

;void my_function(void

)

在上述**中,read_only_variable 是乙個用 const 修飾的全域性變數,它是唯讀的,存放在 flash 中的唯讀資料區域,編譯器會給 read_only_variable 分配乙個位址,並將 2000 這個資料存放到這個位置。data 這個變數將存放到 ram 中的rw區域中 (後面將會進行詳細講解),但是 data 後面的初始值 500 將會被存放到資料複製區域中, 也就是上圖中從下往上的第三個區域。在 my_function 中的變數 x 將會被存放到 ram 中的堆疊中,將 x 賦值為 200 ,200 將被儲存到 flash 裡的 text 中的常量區 (literal valu) 中。str 是乙個 char 型的指標變數,它指向的是字串第乙個字元存放的位置,然而對於字串 string 來講,它是存放在text常量區的,所以指標變數指向這個區域的乙個位址,但是因為它終歸中區域性變數,它指向 flash 的乙個位址,但是其本身還是存放於 ram 中的堆疊上的。

如上圖所示,ram 中包含了如下幾個部分:

棧 (stack) : 存放區域性變數和函式呼叫時的返回位址

堆 (heap) : 由 malloc 申請,由 free 釋放

bss : 存放未初始化或者是初始化為 0 的全域性變數

data : 存放初始化為非 0 值的全域性變數

下面舉乙個簡單的例子來說明變數在各個段中的儲存位置:

#include #include 

int data_var = 500

;int

bss_var0;

int bss_var1 = 0

;static

intstatic_var;

void my_function(void

)

上述變數的命名已經很清楚地表明了變數處於 ram 中的哪乙個段,data_var 是已經初始化的全域性變數,存放在 ram 的 data 區,bss_var0 和 bss_var1是未初始化和初始化為0的全域性變數,他們都存放於 ram 中的 bss段,由 static 修飾的static_var 和 static_var1 都存放於 bss段,區別只在於兩個變數的作用域不同。stack 是在函式內部定義的區域性變數,其存放於 ram 的棧區域,用 const 修飾的區域性變數 value ,雖然他是唯讀的,但是它是儲存於 ram 中的棧中的,這裡也說明一點,並不是所有用 const 修飾的變數都是存放於唯讀變數區的。buffer指標變數用 malloc 函式申請了 10 位元組的記憶體空間,那這10位元組的記憶體空間位於堆中。

堆疊溢位

如果在程式執行的過程中,堆的空間也一直在消耗,同時棧的空間也在增加,那麼這時堆和棧如果碰到一起,那麼就會造成堆疊溢位,從而導致我們的程式跑飛。

stm32中的map檔案分析

在用 keil 編譯 stm32 工程之後,我們會得到乙個 map 檔案,map 檔案的最底部有這麼乙個資訊:

上圖中的各個段是和上文所述是能夠進行對應起來的,正如下面這張表所示:

code  

ro data

rw data 

zi data

executable code

read only data 

data 

bss總結

對於 ram 和 flash 空間都有限的 mcu 來講,了解各個變數在記憶體中的儲存位置是很有必要的,他能夠很好地幫助我們去解決很多問題。

STM32記憶體使用及分配

stack size,一般小工程0x400足夠,我們綜合實驗才設定0x1000就夠用,所以預設無需設定太大。stack size的值根據你程式中區域性變數最大尺寸計算,heap size,如果沒有用到標準庫的malloc,就是廢物,純屬浪費記憶體,所以直接設定為0即可。heap size的值如果程式...

stm32記憶體分配

原文 1 棧區 stack 由編譯器自動分配和釋放,存放函式的引數值 區域性變數的值等,其操作方式類似 於資料結構中的棧。2 堆區 heap 一般由程式設計師分配和釋放,若程式設計師不釋放,程式結束時可能由作業系統 分配 方式類似於資料結構中的鍊錶。3 全域性區 靜態區 static 全域性變數和靜...

STM32的記憶體分配

使用keil編寫 區域性變數和全域性變數分別存放在什麼地方?在乙個函式內部定義的變數是內部變數,它只在本函式範圍內有效,也就是說只有在本函式內才能使用它們,在此函式以外是不能使用這些變數的,這稱為區域性變數。使用區域性變數注意以下問題 不同函式中可以使用相同名字的變數,它們代表不同的物件,互不干擾。...