STM32啓動時RAM空間堆(Heap)和棧(stack)的分配 總結

STM32再啓動的時候RAM首先分配給使用到的全局變量,及調用庫佔用的一些數據(不太清楚是什麼數據)程序員

,而後再將剩餘的空間分配給Heap和stack。數組

 

        如下是網上關於Heap和Stack的說:數據結構

(1)棧區(stack):由編譯器自動分配和釋放,存放函數的參數值、局部變量的值等,其操做方式相似函數

於數據結構中的棧。spa

(2)堆區(heap):通常由程序員分配和釋放,若程序員不釋放,程序結束時可能由操做系統回收。分配操作系統

方式相似於數據結構中的鏈表。.net

(3)全局區(靜態區)(static):全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態指針

變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另外一塊區域。程序結束後由系統自動釋放。調試

(4)文字常量區:常量字符串就是存放在這裏的。code

(5)程序代碼區:存放函數體的二進制代碼。

        一直有疑惑堆區(heap)和全局區是否是在一塊呢,
        今天在研究STM32啓動的時候發現STM32的RAM起始MSP和棧的地址時(stm32的棧是向下增加的,棧頂地址是ram分配的最大空間了),結論如上述,下面截圖詳細說明。

  

上圖是.map文件裏看到的Heap和Stack的地址(空間分配),由圖看出HEAP一行是堆空間分配的開始(從0x20000188),到STACK一行(0x20003188)結束共0x3000字節 (12K)的空間。

         Stack_Mem一行(0x20003188)到棧頂地址__initial_sp(0x20003588)一共是0x400字節(1K)空間。他們的大小正是我在起始文件startup_stm32f10x_md.s文件裏分配的大小。以下圖:

 

嗯,是一致的。

按stm32的datasheet上說,其RAM是從0x20000000開始的。下面是datasheet截圖:

 

而個人工程裏堆區和棧區是從0x20000188開始的,那麼0x20000188前面的空間部分被什麼佔用了呢。起始從第一個.map文件截圖能夠看出來,首先是被全局變量佔用了一部分0x58=88Byte。

      

這部分大小正好跟個人工程所用全局變量大小是一直的,以下圖編譯工程的結果RW-data大小便是工程所用到的全局變量大小

 

至於0x20000188-0x20000058=剩下的空間是什麼,我猜想應該是庫佔用的。由於後綴是libspace(.bss),請看上圖。

至此分析結束
————————————————
版權聲明:本文爲CSDN博主「吃不了這碗飯」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接及本聲明。
原文連接:https://blog.csdn.net/qq_29119171/article/details/53764823

 

 

原文地址:http://blog.csdn.net/slj_win/article/details/16906141

文章排版不是很好,可是寫的仍是頗有道理的。

 

關於堆和棧已是程序員的一個月經話題,大部分有是基於os層來聊的。


那麼,在赤裸裸的單片機下的堆和棧是什麼樣的分佈呢?如下是網摘:

剛接手STM32時,你只編寫一個


  1.  
    int main()
  2.  
    {
  3.  
    while(1);
  4.  
    }

BUILD://Program Size: Code=340 RO-data=252 RW-data=0 ZI-data=1632 


編譯後,就會發現這麼個程序已用了1600多的RAM,要是在51單片機上,會心疼死了,這1600多的RAM跑哪兒去了,


分析map,你會發現是堆和棧佔用的,在startup_stm32f10x_md.s文件(這個是stm32的啓動文件)中,它的前面幾行就有以上定義,


這下該明白了吧。


Stack_Size   EQU   0x00000400


Heap_Size   EQU   0x00000200


如下引用網上資料 理解堆和棧的區別


(1)棧區(stack):由編譯器自動分配和釋放,存放函數的參數值、局部變量的值等,其操做方式相似於數據結構中的棧。


(2)堆區(heap):通常由程序員分配和釋放,若程序員不釋放,程序結束時可能由操做系統回收。分配方式相似於數據結構中的鏈表。


(3)全局區(靜態區)(static):全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另外一塊區域。程序結束後由系統自動釋放。

 

(4)文字常量區:常量字符串就是存放在這裏的。

 

(5)程序代碼區:存放函數體的二進制代碼。



例如:

  1. int a=0; //全局初始化區 
  2. char *p1; //全局未初始化區
  3. main()
  4. {
  5. int b; //棧
  6. char s[]="abc"; //棧
  7. char *p3= "1234567"; //在文字常量區Flash
  8. static int c =0 ; //靜態初始化區
  9. p1= ( char *)malloc(10); //堆區
  10. strcpy(p1,"123456"); //"123456"放在常量區
    }





因此堆和棧的區別:


stack的空間由操做系統自動分配/釋放,heap上的空間手動分配/釋放。


stack的空間有限,heap是很大的自由存儲區(heap雖然有很大的存儲區,可是這個存儲區並非無限大的,在stm32中,heap區的最大值由SRAM區決定,而SRAM區的大小能夠參考具體的數據手冊)。


程序在編譯期和函數分配內存都是在棧上進行,且程序運行中函數調用時參數的傳遞也是在棧上進行。


------------------------------------------------------------------------------------------------------


1.堆和棧大小


定義大小在startup_stm32f2xx.s (這個地方應該是有錯,定義的大小是在startup_stm32f10x_hd.s,也就是啓動文件中)


Stack_Size  EQU  0x00000400 


AREA  STACK, NOINIT, READWRITE, ALIGN=3 
Stack_Mem  SPACE  Stack_Size 
__initial_sp


; Heap Configuration 
;  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> 
;


Heap_Size  EQU  0x00000200  //這裏就是分配的堆空間大小


AREA  HEAP, NOINIT, READWRITE, ALIGN=3 
__heap_base


2.堆和棧位置


經過MAP文件可知


HEAP  0x200106f8  Section  512  startup_stm32f2xx.o(HEAP) 
STACK  0x200108f8  Section  1024  startup_stm32f2xx.o(STACK)


__heap_base  0x200106f8  Data  0  startup_stm32f2xx.o(HEAP) 
__heap_limit  0x200108f8  Data  0  startup_stm32f2xx.o(HEAP) 
__initial_sp  0x20010cf8  Data  0  startup_stm32f2xx.o(STACK)


顯然 Cortex-m3資料可知:__initial_sp是堆棧指針,它就是FLASH的0x8000000地址前面4個字節(它根據堆棧大小,由編譯器自動生成)


顯然堆和棧是相鄰的。

 

 

3.堆和棧空間分配棧:向低地址擴展堆:向高地址擴展顯然若是依次定義變量,先定義的棧變量的內存地址比後定義的棧變量的內存地址要大先定義的堆變量的內存地址比後定義的堆變量的內存地址要小4.堆和棧變量棧:臨時變量,退出該做用域就會自動釋放堆:malloc變量,經過free函數釋放另外:堆棧溢出,編譯不會提示,須要注意 ------------------------------------------------------------------------------------------------------ 若是使用了HEAP,則必須設置HEAP大小。 若是是STACK,能夠設置爲0,不影響程序運行。 IAR STM8定義STACK,是預先在RAM尾端分配一個字節的區域做爲堆棧預留區域。 當程序靜態變量,全局變量,或者堆與預留堆棧區域有衝突,編譯器鏈接的時候就會報錯。 你能夠吧STACK設置爲0,並不影響運行。(會影響調試,調試會報堆棧溢出警告)。 其實不必這麼作。 通常程序,(在容許範圍內)設置多少STACK,並不影響程序真實使用的RAM大小, (能夠試驗,把STACK設置多少,編譯出來的HEX文件都是同樣), 程序仍是按照它本來的狀態使用RAM,把STACK設置爲0,並非真實地減小RAM使用。 僅僅是欺騙一下編譯器,讓程序表面上看起來少用了RAM。 而設置必定size的STACK,也並非真的就多使用了RAM,只是讓編譯器幫你 檢查一下,是否可以保證有size大小的RAM沒有被佔用,能夠用來做爲堆棧。 以上僅針對IAR STM8. ------------------------------------------------------------------------------------------------------ 從以上網摘來看單片機的堆和棧是分配在RAM裏的,有多是內部也有多是外部,能夠讀寫;(堆在stm32是分配在SRAM中的) 棧:存函數的臨時變量,即局部變量,函數返回時隨時有可能被其餘函數棧用。因此棧是一種分時輪流使用的存儲區,      編譯器裏定義的Stack_Size,是爲了限定函數的局部數據活動的範圍,操過這麼範圍有能夠跑飛,也就是棧溢出;     Stack_Size不影響Hex,更不影響Hex怎麼運行的,只是在Debug調試時會提示錯。棧溢出也有是超過了國界進行     活動,只要老外沒有意見,你能夠接着玩,有老外不讓你玩,你就的得死,或是你們都死(互相撕殺),有的人寫    單片機代碼在函數裏定義一個大數組 int buf[8192],棧要是小於8192是會死的很慘。 堆:存的是全局變量,這變量理論上是全部函數均可以訪問的,全局變量有的有初始值,但這個值不是存在RAM裏的,是     存在Hex裏,下載到Flash裏,上電由代碼(編譯器生成的彙編代碼)搬過去的。有的人很「霸道」,上電就霸佔已一塊很    大的RAM(Heap_Size),做爲己有(malloc_init),別人用只能經過他們管家借(malloc),用完還得換(free)。因此      一旦有「霸道」的人出現是編譯器裏必須定義Heap_Size,不然和他管家借也沒有用。 總之:堆和棧有存在RAM裏,他兩各分多少看函數需求,可是他兩的總值不能超過單片機硬件的實際RAM尺寸,不然只能     到海里玩(淹死了)或是本身打造船接着玩(外擴RAM)。

相關文章
相關標籤/搜索