0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

深入理解Cortex-M內(nèi)存管理(GCC)

嵌入式大雜燴 ? 來(lái)源:嵌入式大雜燴 ? 作者:嵌入式大雜燴 ? 2023-04-27 10:58 ? 次閱讀

在討論Cortex-M的內(nèi)存之前,先來(lái)看看Cortex-M的存儲(chǔ)器系統(tǒng),我們知道,Cortex-M系列的處理器,大都可以對(duì)32的存儲(chǔ)器進(jìn)行尋址,因此存儲(chǔ)器的尋址空間能夠達(dá)到4G,這就意味著指定和數(shù)據(jù)共用相同的地址空間,也就是將程序存儲(chǔ)器、數(shù)據(jù)存儲(chǔ)器、寄存器和輸入輸出端口被組織在同一個(gè)4GB的線性地址空間內(nèi)。數(shù)據(jù)字節(jié)以小端格式存放在存儲(chǔ)器中。一個(gè)字里的最低地址字節(jié)被認(rèn)為是該字的最低有效字節(jié),而最高地址字節(jié)是最高有效字節(jié)。

1 Cortex-M存儲(chǔ)器架構(gòu)

4G的地址空間就是地址編碼的范圍。所謂編碼就是對(duì)每一個(gè)程序存儲(chǔ)器、數(shù)據(jù)存儲(chǔ)器、寄存器和輸入輸出端口(一個(gè)字節(jié))分配一個(gè)唯一的地址號(hào)碼,這個(gè)過(guò)程又叫做“編址”或者“地址映射”。這個(gè)過(guò)程就好像在日常生活中我們給每家每戶分配一個(gè)地址門(mén)牌號(hào)。與編碼相對(duì)應(yīng)的是“尋址”過(guò)程——分配一個(gè)地址號(hào)碼給一個(gè)存儲(chǔ)單元的目的是為了便于找到它,完成數(shù)據(jù)的讀寫(xiě),這就是“尋址”,因此地址空間有時(shí)候又被稱(chēng)作“尋址空間”。

有了4G的可尋址空間,我們就可通過(guò)尋址來(lái)操作相應(yīng)的地址對(duì)象。這就需要將程序存儲(chǔ)器、數(shù)據(jù)存儲(chǔ)器、寄存器和輸入輸出端口進(jìn)行統(tǒng)一編號(hào),也就是存儲(chǔ)器映射。

存儲(chǔ)器映射是指把芯片中或芯片外的FLASH,RAM,外設(shè),BOOTBLOCK等進(jìn)行統(tǒng)一編址。即用地址來(lái)表示對(duì)象。這個(gè)地址絕大多數(shù)是由廠家規(guī)定好的,用戶只能用而不能改。用戶只能在掛外部RAM或FLASH的情況下可進(jìn)行自定義。

如下圖,是Cortex-M3存儲(chǔ)器映射結(jié)構(gòu)圖。

1682564017434e4w7hhxwn2

Cortex-M3是32位的內(nèi)核,因此其PC指針可以指向2^32=4G的地址空間,也就是0x0000_0000——0xFFFF_FFFF這一大塊空間。根據(jù)圖中描述,Cortex-M3內(nèi)核將0x0000_0000——0xFFFF_FFFF這塊4G大小的空間分成8大塊:代碼、SRAM、外設(shè)、外部RAM、外部設(shè)備、專(zhuān)用外設(shè)總線-內(nèi)部、專(zhuān)用外設(shè)總線-外部、特定廠商等,因此使用該內(nèi)核的設(shè)計(jì)者必須按照這個(gè)進(jìn)行各自芯片的存儲(chǔ)器結(jié)構(gòu)設(shè)計(jì)。

首先,我們對(duì)比一下Cortex-M3存儲(chǔ)器結(jié)構(gòu)和STM32存儲(chǔ)器結(jié)構(gòu):

C:\\Users\\ouxiaolong\\Desktop\\科技部哪幾種.jpg

圖中可以很清晰的看到,STM32的存儲(chǔ)器結(jié)構(gòu)和Cortex-M3的很相似,不同的是,STM32加入了很多實(shí)際的東西,如:Flash、SRAM等。只有加入了這些東西,才能成為一個(gè)擁有實(shí)際意義的、可以工作的處理芯片——STM32。

STM32的存儲(chǔ)器地址空間被劃分為大小相等的8塊區(qū)域,每塊區(qū)域大小為512MB。

地址范圍 描述
0x0000 0000 ~0x2000 0000 根據(jù)啟動(dòng)引腳的狀態(tài)決定哪個(gè)存儲(chǔ)空間被映射到此處。 片內(nèi)系統(tǒng)存儲(chǔ)區(qū)起始地址:0x1fff0000(2K字節(jié)的空間)
0x2000 0000 ~0x4000 0000 SRAM區(qū),64K,其中位帶別名區(qū)首地址為:0x2200 0000
0x4000 0000 ~0x6000 0000 用于片內(nèi)外設(shè),外設(shè)寄存器的別名區(qū)首地址:0x4200 0000
0x6000 0000 ~0x8000 0000
0x8000 0000 ~0xa000 0000 片上flash存儲(chǔ)區(qū)512M
0xa000 0000 ~0xc000 0000
0xc000 0000 ~0xe000 0000
0xe000 0000 ~0xffff ffff

對(duì)STM32存儲(chǔ)器知識(shí)的掌握,實(shí)際上就是對(duì)Flash和SRAM這兩個(gè)區(qū)域知識(shí)的掌握。由STM32的系統(tǒng)結(jié)構(gòu)可以看出,F(xiàn)lash和SRAM這兩個(gè)區(qū)域分別由ICode總線和DCode總線與處理器通信,以此完成相應(yīng)的數(shù)據(jù)交換。

168256401840268iwud23g6

當(dāng)然啦,其他Cortex-M的處理和STM32的也是類(lèi)似的,比如GD32、CH32等。

下面將重點(diǎn)描述Flash和SRAM的知識(shí)。

1.1 Cortex-M的SRAM

RAM隨機(jī)存儲(chǔ)器(Random Access Memory)表示既可以從中讀取數(shù)據(jù),也可以寫(xiě)入數(shù)據(jù)。當(dāng)機(jī)器電源關(guān)閉時(shí),存于其中的數(shù)據(jù)就會(huì)丟失。比如電腦的內(nèi)存條。

RAM有兩大類(lèi),一種稱(chēng)為靜態(tài)RAM(Static RAM/SRAM),SRAM速度非??欤悄壳白x寫(xiě)最快的存儲(chǔ)設(shè)備了,但是它也非常昂貴,所以只在要求很苛刻的地方使用,譬如CPU的一級(jí)緩沖,二級(jí)緩沖。另一種稱(chēng)為動(dòng)態(tài)RAM(Dynamic RAM/DRAM),DRAM保留數(shù)據(jù)的時(shí)間很短,速度也比SRAM慢,不過(guò)它還是比任何的ROM都要快,但從價(jià)格上來(lái)說(shuō)DRAM相比SRAM要便宜很多,計(jì)算機(jī)內(nèi)存就是DRAM的。

DRAM分為很多種,常見(jiàn)的主要有FPRAM/FastPage、EDORAM、SDRAM、DDR RAM、RDRAM、SGRAM以及WRAM等,這里介紹其中的一種DDR RAM。

DDR RAM(Date-Rate RAM)也稱(chēng)作DDR SDRAM,這種改進(jìn)型的RAM和SDRAM是基本一樣的,不同之處在于它可以在一個(gè)時(shí)鐘讀寫(xiě)兩次數(shù)據(jù),這樣就使得數(shù)據(jù)傳輸速度加倍了。這是目前電腦中用得最多的內(nèi)存,而且它有著成本優(yōu)勢(shì),事實(shí)上擊敗了Intel的另外一種內(nèi)存標(biāo)準(zhǔn)-Rambus DRAM。在很多高端的顯卡上,也配備了高速DDR RAM來(lái)提高帶寬,這可以大幅度提高3D加速卡的像素渲染能力。

為什么需要RAM,因?yàn)橄鄬?duì)FlASH而言,RAM的速度快很多,所有數(shù)據(jù)在FLASH里面讀取太慢了,為了加快速度,就把一些需要和CPU交換的數(shù)據(jù)讀到RAM里來(lái)執(zhí)行。

STM32單片機(jī)內(nèi)部的 RAM 為 SRAM。不同類(lèi)型的Cortex-M單片機(jī)的SRAM大小是不一樣的,但起始地址都是0x2000 0000,終止地址都是0x2000 0000+其固定的容量大小。SRAM相對(duì)容量小,速度快,掉電數(shù)據(jù)丟失,其作用是用來(lái)存取各種動(dòng)態(tài)的輸入輸出數(shù)據(jù)、中間計(jì)算結(jié)果以及與外部存儲(chǔ)器交換的數(shù)據(jù)和暫存數(shù)據(jù)。設(shè)備斷電后,SRAM中存儲(chǔ)的數(shù)據(jù)就會(huì)丟失。

1.2 Cortex-M的Flash

Cortex-M的Flash,嚴(yán)格說(shuō),應(yīng)該是Flash模塊。該Flash模塊包括: Flash主存儲(chǔ)區(qū)(Main memory)、Flash信息區(qū)(Information block),以及Flash存儲(chǔ)接口寄存器區(qū)(Flash memory interface) 。三個(gè)組成部分分別在0x0000 0000——0xFFFF FFFF不同的區(qū)域。下面介紹STM32的Flash,如下表所示。

1682564019028gm87ecnlid

STM32的閃存模塊由:__主存儲(chǔ)器、信息塊和閃存儲(chǔ)器塊__3部分組成。

主存儲(chǔ)器 ,該部分用來(lái)存放代碼和數(shù)據(jù)常數(shù)(如加const類(lèi)型的數(shù)據(jù))。對(duì)于大容量產(chǎn)品,其被劃分為256頁(yè),每頁(yè)2K,注意,小容量和中容量產(chǎn)品則每頁(yè)只有1K字節(jié)。主存儲(chǔ)起的起始地址為0X08000000,B0、B1都接GND的時(shí)候,就從0X08000000開(kāi)始運(yùn)行代碼。

信息塊 ,該部分分為2個(gè)部分,其中啟動(dòng)程序代碼,是用來(lái)存儲(chǔ)ST自帶的啟動(dòng)程序,用于串口下載,當(dāng)B0接3.3V,B1接GND時(shí),運(yùn)行的就這部分代碼,用戶選擇字節(jié),則一般用于配置保護(hù)等功能。

閃存儲(chǔ)器塊 ,該部分用于控制閃存儲(chǔ)器讀取等,是整個(gè)閃存儲(chǔ)器的控制機(jī)構(gòu)。

對(duì)于主存儲(chǔ)器和信息塊的寫(xiě)入有內(nèi)嵌的閃存編程管理;編程與擦除的高壓由內(nèi)部產(chǎn)生。

在執(zhí)行閃存寫(xiě)操作時(shí),任何對(duì)閃存的讀操作都會(huì)鎖定總線,在寫(xiě)完成后才能正確進(jìn)行,在進(jìn)行讀取或擦除操作時(shí),不能進(jìn)行代碼或者數(shù)據(jù)的讀取操作。

2 C程序內(nèi)存分析

在C/C++程序中,編譯的程序占用內(nèi)存分為5個(gè)區(qū),分別為_(kāi)_棧區(qū)、堆區(qū)、全局/靜態(tài)存儲(chǔ)區(qū)、常量存儲(chǔ)區(qū)、代碼區(qū)__。

1682564019718t41ik6fneo

1.Text段(Code Segment/Text Segment,代碼段) :通常是指用來(lái)存放程序執(zhí)行代碼的一塊內(nèi)存區(qū)域,也就是存放CPU執(zhí)行的機(jī)器指令(machine instructions)。這部分區(qū)域的大小在程序運(yùn)行前就已經(jīng)確定,并且內(nèi)存區(qū)域通常屬于只讀(某些架構(gòu)也允許代碼段為可寫(xiě),即允許修改程序)。在代碼段中,也有可能包含一些只讀的常數(shù)變量,例如字符串常量等。

2.全局初始化數(shù)據(jù)區(qū)/靜態(tài)數(shù)據(jù)區(qū)(Initialized data segment/Data segment) :該區(qū)包含了在程序中明確被初始化的全局變量、靜態(tài)變量(包括全局靜態(tài)變量和局部靜態(tài)變量)和常量數(shù)據(jù)(如字符串常量)。數(shù)據(jù)段屬于靜態(tài)內(nèi)存分配。static聲明的變量放在data段。

3.BSS段(Block Started by Symbol) :BSS段通常是指用來(lái)存放程序中未初始化的全局變量的一塊內(nèi)存區(qū)域。BSS段屬于靜態(tài)內(nèi)存分配。

4.堆(heap) :堆是用于存放程序運(yùn)行中被動(dòng)態(tài)分配的內(nèi)存段,它的大小并不固定,可動(dòng)態(tài)擴(kuò)張或縮減。也就是常說(shuō)的用malloc,calloc, realloc 等函數(shù)分配的變量空間是在堆上。當(dāng)程序調(diào)用malloc等函數(shù)分配內(nèi)存時(shí),新分配的內(nèi)存就被動(dòng)態(tài)添加到堆上(堆被擴(kuò)張);當(dāng)利用free等函數(shù)釋放內(nèi)存時(shí),被釋放的內(nèi)存從堆中被剔除(堆被縮減)。

5.棧(stack) :棧又稱(chēng)堆棧,是用戶存放程序臨時(shí)創(chuàng)建的局部變量,也就是說(shuō)我們函數(shù)括弧“{}”中定義的變量(但不包括static聲明的變量,static意味著在數(shù)據(jù)段中存放變量)。除此以外,在函數(shù)被調(diào)用時(shí),其參數(shù)也會(huì)被壓入發(fā)起調(diào)用的進(jìn)程棧中,并且待到調(diào)用結(jié)束后,函數(shù)的返回值也會(huì)被存放回棧中。由于棧的先進(jìn)先出(FIFO)特點(diǎn),所以棧特別方便用來(lái)保存/恢復(fù)調(diào)用現(xiàn)場(chǎng)。從這個(gè)意義上講,我們可以把堆??闯梢粋€(gè)寄存、交換臨時(shí)數(shù)據(jù)的內(nèi)存區(qū)。

一個(gè)程序本質(zhì)上都是由 __bss段、data段、text段__三個(gè)組成的。

在C/C++程序編譯完成之后,已初始化的全局變量保存在data 段中,未初始化的全局變量保存在bss 段中。

text和data段都在可執(zhí)行文件中(在嵌入式系統(tǒng)里一般是固化在鏡像文件中),由系統(tǒng)從可執(zhí)行文件中加載;而bss段不在可執(zhí)行文件中,由系統(tǒng)初始化。

3 STM32程序的存儲(chǔ)分配

3.1 程序所占RAM和Flash大小分析

為例調(diào)試方便,這里使用一個(gè)裸機(jī)串口例子,關(guān)于串口的使用請(qǐng)參看筆者博文:

串口通信:https://bruceou.blog.csdn.net/article/details/79341769

使用GCC編譯代碼,編譯信息如下:

16825640200889qfp6m8i9a

其中:

  • text 代表執(zhí)行的代碼,程序中所有的函數(shù)都位于此處。當(dāng)然還包括RO-data(Read Only)代表只讀數(shù)據(jù),程序中所定義的全局常量數(shù)據(jù)和字符串都位于此處,如const型。
  • __data__代表已初始化的讀寫(xiě)數(shù)據(jù),程序中定義并且初始化的全局變量和靜態(tài)變量位于此處。
  • bss代表未初始化的讀寫(xiě)數(shù)據(jù),程序中定義了但沒(méi)有初始化的全局變量和靜態(tài)變量位于此處。GCC編譯器默認(rèn)是把你沒(méi)有初始化的變量都賦值為例0。即上述的bss段。

值得注意的是,這些參數(shù)的單位是Byte。

text和data兩個(gè)段需要燒錄到FLASH等非易失性器件中。

data段需要燒錄到FLASH中,而bss段則不用,但在運(yùn)行時(shí),它們都必須裝載到可讀可寫(xiě)的RAM中。

因此我們可以計(jì)算出FLASH和RAM的大?。?/p>

Flash = test + data

RAM = data + bss

這就要涉及到程序的兩種狀態(tài):加載域和運(yùn)行域。

[]()[]()Figure ? 程序的加載域和運(yùn)行域

加載域 :向Flash中下載程序時(shí),其實(shí)僅僅下載的是text+data的內(nèi)容,意思就是說(shuō),在掉電情況下,F(xiàn)lash里面的內(nèi)存僅包含text+data的內(nèi)容。

運(yùn)行域 :當(dāng)上電后,程序運(yùn)行時(shí),首先程序會(huì)從特定的地址進(jìn)行啟動(dòng),啟動(dòng)時(shí)會(huì)將data的數(shù)據(jù)加載到SRAM中,單片機(jī)的test區(qū)域不需要加載到 SRAM,內(nèi)核直接從 FLASH 讀取指令運(yùn)行。那bss的數(shù)據(jù)怎么辦呢?對(duì)于初始值為0全局變量來(lái)說(shuō),因?yàn)橐贑ode區(qū)要調(diào)用該全局變量,所以肯定要對(duì)其進(jìn)行描述,程序運(yùn)行時(shí)就知道了,原來(lái)你是初始值為0的全局變量呀,然后就在SRAM區(qū)給你分配了一段固定區(qū)域的地址;對(duì)于局部變量來(lái)說(shuō),會(huì)自動(dòng)分配大小。bss有統(tǒng)計(jì)作用,并且SRAM中一段特定的區(qū)域是運(yùn)行bss數(shù)據(jù),data +bss就是程序運(yùn)行總共會(huì)占用SRAM的長(zhǎng)度,生成局部變量的??臻g包含在bss區(qū)的范圍。

3.2 程序堆棧使用分析

我們知道,程序運(yùn)行需要占用的大小是RAM = data + bss,而堆棧的大小是程序開(kāi)始運(yùn)行后才能確定的。

那么堆和棧到底能占用多大呢,堆棧的大小是在STM32F103ZETx_FLASH.ld中設(shè)置的,這里以STM32F103ZET6為例進(jìn)行分析,其內(nèi)部棧的大小為1KB,堆的大小為0.5KB。

1682564020921379dug4zyh

使用objdump查看elf文件:

1682564021308yi8wwzpnm8

堆棧段起始地址為0x2000 002c,大小為0x604,這0x4又是怎么來(lái)的?這里查看map文件。

1682564021626x68xagxl0m

堆占用了0x200字節(jié),棧占用了0x400字節(jié),而剩下的0x4字節(jié)來(lái)自于 ALIGN(0x8),即8字節(jié)對(duì)齊,因?yàn)槎褩6尉o跟.bss段之后,那首地址應(yīng)該是0x2000 0070,但是規(guī)定了8字節(jié)對(duì)齊,所以最小為32,即需要補(bǔ)上4個(gè)字節(jié),所以堆棧段起始地址應(yīng)該是0x2000 00F4。

【注】棧:向低地址擴(kuò)展,堆:向高地址擴(kuò)展。如果依次定義變量,先定義的棧變量的內(nèi)存地址比后定義的棧變量的內(nèi)存地址要大,先定義的堆變量的內(nèi)存地址比后定義的堆變量的內(nèi)存地址要小。

【Tips】

1、堆棧的大小在編譯器編譯之后是不知道的,只有運(yùn)行的時(shí)候才知道,所以需要注意一點(diǎn),就是別造成堆棧溢出了,不然就會(huì)發(fā)生hard fault錯(cuò)誤。

2、所有在處理的函數(shù),包括函數(shù)嵌套,遞歸,等等,都是從這個(gè)“?!崩锩?,來(lái)分配的。所以,如果棧大小為2K,一個(gè)函數(shù)的局部變量過(guò)多,比如在函數(shù)里面定義一個(gè)char buf[512],這一下就占了1/4的棧大小了,再在其他函數(shù)里面來(lái)搞兩下,程序崩潰是很容易的事情,這時(shí)候,一般你會(huì)進(jìn)入到hardfault…。

3、STM32的棧,是向下生長(zhǎng)的。事實(shí)上,一般CPU的棧增長(zhǎng)方向,都是向下的。而堆的生長(zhǎng)方向,都是向上的。堆和棧,只是他們各自的起始地址和增長(zhǎng)方向不同,他們沒(méi)有一個(gè)固定的界限,所以一旦堆棧沖突,系統(tǒng)就到了崩潰的時(shí)候了。

4、程序中的常量,如果沒(méi)加const也會(huì)編譯到SRAM里,加了const會(huì)被編譯到flash中。

3.3 實(shí)例代碼分析

前面分析了那么多,下面通過(guò)一個(gè)實(shí)例來(lái)驗(yàn)證前面的分析。

main.c函數(shù)代碼如下:

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include 
#include 
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */
uint8_t buffer[10];//聲明了一個(gè)初始化為0的全局?jǐn)?shù)組
uint8_t data = 1;//初始化的全局變量

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
  uint8_t stack_i; //未初始化的局部變量,
  uint8_t stack_j = 1; //初始化的局部變量

  uint8_t *pHeap1 = (uint8_t *)malloc(10);//指針pHeap指向堆區(qū)分配了一個(gè)uint8_t類(lèi)型10大小的空間
  uint8_t *pHeap2 = (uint8_t *)malloc(10);

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
   
  printf("First address of uninitialized global variable buffer: %p\\r\\n", buffer);
  printf("Address of initialized global variable data: %p\\r\\n", &data);
  printf("Address of uninitialized local variable stack_i: %p\\r\\n", &stack_i);
  printf("Address of uninitialized local variable stack_j: %p\\r\\n", &stack_j);
    
  printf("The first address of pHeap1 in the heap: %p\\r\\n", pHeap1);
  printf("The first address of pHeap2 in the heap: %p\\r\\n", pHeap2);

  free(pHeap1);
  free(pHeap2);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
    HAL_Delay(500);
  }
  /* USER CODE END 3 */
}

編譯后內(nèi)存分配如下:

1682564021945e4xdx34h1h

運(yùn)行程序,打印信息如下:

1682564022324vi2833tz0a

data是初始化的全局變量,在.data區(qū);buffer是未初始化的全局變量,在.bss區(qū);pHeap是通過(guò)malloc分配的空間,在堆區(qū),逐漸增加;局部變量都在棧區(qū),增加減小。

4 堆棧的使用總結(jié)

堆的使用:

1、堆的使用是要結(jié)合malloc函數(shù),即使用一次malloc所得到的內(nèi)存空間既是屬于堆的空間。

2、堆的增長(zhǎng)方向是向上,所以malloc申請(qǐng)的地址也是越來(lái)越大的,前提是連續(xù)申請(qǐng)且在最后一次申請(qǐng)后再釋放內(nèi)存(free)。則第一次申請(qǐng)的地址永遠(yuǎn)小于后面申請(qǐng)的地址。

3、堆是不連續(xù)的,由于RAM中還存在局部變量,代碼段和棧等等,所以動(dòng)態(tài)分配的內(nèi)存是取暫時(shí)空閑的內(nèi)存,而不是預(yù)先劃出一塊區(qū)域,這就是動(dòng)態(tài)分配內(nèi)存的好處。

4、使用堆的壞處,由于使用malloc申請(qǐng)內(nèi)存時(shí),不單只申請(qǐng)了所需的大小空間,還要額外暫用管理這部分空間的內(nèi)存,而釋放時(shí)又只釋放申請(qǐng)的內(nèi)存,所以使用堆會(huì)引入內(nèi)存碎片。當(dāng)然如果不是在短時(shí)間內(nèi)頻繁的使用malloc申請(qǐng)和free釋放內(nèi)存,那么操作系統(tǒng)就有足夠的時(shí)間來(lái)回收碎片空間。

棧的使用:

1、由編譯器分配,目的是將RAM劃分處一塊區(qū)域供程序運(yùn)行時(shí)的局部變量參數(shù)等使用;

2、棧是一塊連續(xù)的內(nèi)存空間,由上往下增長(zhǎng),即使用棧時(shí)地址是會(huì)越來(lái)越小的,如先聲明的局部變量比后聲明的地址要高;

3、棧是由程序(操作系統(tǒng))自動(dòng)分配,不會(huì)有內(nèi)存碎片的問(wèn)題;

4、棧的壞處:棧是固定且連續(xù)的一個(gè)大小,如果使用局部變量等超出了棧的大小則會(huì)造成內(nèi)存溢出,而編譯器通常是發(fā)現(xiàn)不了的,只有當(dāng)程序運(yùn)行到那個(gè)函數(shù)時(shí)才會(huì)發(fā)生的。這就會(huì)引入很難查找的bug。另外如如果使用malloc申請(qǐng)的內(nèi)存不規(guī)范使用,當(dāng)釋放內(nèi)存后,沒(méi)將指針地址清空,仍指向那個(gè)地址剛好是棧的地址,則會(huì)造成越界訪問(wèn)。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 存儲(chǔ)器
    +關(guān)注

    關(guān)注

    38

    文章

    7492

    瀏覽量

    163834
  • GCC
    GCC
    +關(guān)注

    關(guān)注

    0

    文章

    107

    瀏覽量

    24844
  • 內(nèi)存管理
    +關(guān)注

    關(guān)注

    0

    文章

    168

    瀏覽量

    14139
  • Cortex-M
    +關(guān)注

    關(guān)注

    2

    文章

    229

    瀏覽量

    29763
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    深入理解Android

    深入理解Android
    發(fā)表于 08-20 15:30

    深入理解和實(shí)現(xiàn)RTOS_連載

    ,那里有更詳細(xì)的注釋?zhuān)沂侨形牡摹?b class='flag-5'>深入理解和實(shí)現(xiàn)RTOS_連載5_多任務(wù)機(jī)制應(yīng)用演示本節(jié)我們通過(guò)在評(píng)估板上的實(shí)例來(lái)演示有關(guān)線程調(diào)度和管理的API。因?yàn)槊總€(gè)例子中都包括了線程的創(chuàng)建,所以這里就不單獨(dú)再介紹如何創(chuàng)建線程。示例程序盡量設(shè)計(jì)的簡(jiǎn)單,主要依靠評(píng)估板上的LED 燈
    發(fā)表于 05-29 11:20

    深入理解和實(shí)現(xiàn)RTOS_連載

    和trcohili的帖子。trochili rtos完全是作者興趣所在,且行且堅(jiān)持,比沒(méi)有duo。深入理解和實(shí)現(xiàn)RTOS_連載1_RTOS的前生今世今天發(fā)布的是第一篇,"RTOS的前生今世"
    發(fā)表于 05-30 01:02

    深入理解LINUX內(nèi)存管理》學(xué)習(xí)筆記

    深入理解LINUX內(nèi)存管理》學(xué)習(xí)筆記1
    發(fā)表于 11-07 10:20

    Cortex-M內(nèi)核的GCC編譯器

    下載ARM官方對(duì)應(yīng)Cortex-M內(nèi)核的GCC編譯器
    發(fā)表于 08-24 06:44

    對(duì)棧的深入理解

    為什么要深入理解棧?做C語(yǔ)言開(kāi)發(fā)如果棧設(shè)置不合理或者使用不對(duì),棧就會(huì)溢出,溢出就會(huì)遇到無(wú)法預(yù)測(cè)亂飛現(xiàn)象。所以對(duì)棧的深入理解是非常重要的。注:動(dòng)畫(huà)如果看不清楚可以電腦看更清晰啥是棧先來(lái)看一段動(dòng)畫(huà):沒(méi)有
    發(fā)表于 02-15 07:01

    為什么要深入理解

    [導(dǎo)讀] 從這篇文章開(kāi)始,將會(huì)不定期更新關(guān)于嵌入式C語(yǔ)言編程相關(guān)的個(gè)人認(rèn)為比較重要的知識(shí)點(diǎn),或者踩過(guò)的坑。為什么要深入理解棧?做C語(yǔ)言開(kāi)發(fā)如果棧設(shè)置不合理或者使用不對(duì),棧就會(huì)溢出,溢出就會(huì)遇到無(wú)法
    發(fā)表于 02-15 06:09

    深入理解Linux虛擬內(nèi)存管理_愛(ài)爾蘭/戈?duì)柭?/a>

    電子發(fā)燒友網(wǎng)站提供《深入理解Linux虛擬內(nèi)存管理_愛(ài)爾蘭/戈?duì)柭?txt》資料免費(fèi)下載
    發(fā)表于 02-09 15:19 ?0次下載

    深入理解Android》文前

    深入理解Android》文前
    發(fā)表于 03-19 11:23 ?0次下載

    深入理解Android:卷I》

    深入理解Android:卷I》
    發(fā)表于 03-19 11:23 ?0次下載

    深入理解Android網(wǎng)絡(luò)編程

    深入理解Android網(wǎng)絡(luò)編程
    發(fā)表于 03-19 11:26 ?1次下載

    深入理解C指針(C/C++程序員進(jìn)階必備,透徹理解指針與內(nèi)存管理)pdf

    深入理解C指針
    發(fā)表于 03-21 09:42 ?118次下載

    Cortex-M內(nèi)核的MPU內(nèi)存保護(hù)單元

    講講Cortex-M內(nèi)核的MPU內(nèi)存保護(hù)單元
    的頭像 發(fā)表于 03-04 11:17 ?3686次閱讀
    <b class='flag-5'>Cortex-M</b>內(nèi)核的MPU<b class='flag-5'>內(nèi)存</b>保護(hù)單元

    一點(diǎn)理解之 CmBacktrace: ARM Cortex-M 系列 MCU 錯(cuò)誤追蹤庫(kù)

    一點(diǎn)理解之 CmBacktrace: ARM Cortex-M 系列 MCU 錯(cuò)誤追蹤庫(kù)
    發(fā)表于 11-30 19:51 ?10次下載
    一點(diǎn)<b class='flag-5'>理解</b>之 CmBacktrace: ARM <b class='flag-5'>Cortex-M</b> 系列 MCU 錯(cuò)誤追蹤庫(kù)

    深入理解Cortex-M內(nèi)存管理(Keil)

    在討論Cortex-M內(nèi)存之前,先來(lái)看看Cortex-M的存儲(chǔ)器系統(tǒng),我們知道,Cortex-M系列的處理器,大都可以對(duì)32的存儲(chǔ)器進(jìn)行尋址,因此存儲(chǔ)器的尋址空間能夠達(dá)到4G,這就意
    的頭像 發(fā)表于 04-27 10:41 ?5261次閱讀
    <b class='flag-5'>深入理解</b><b class='flag-5'>Cortex-M</b><b class='flag-5'>內(nèi)存</b><b class='flag-5'>管理</b>(Keil)