<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > [跟我學(xué)嵌入式開(kāi)發(fā)] 堆和棧

[跟我學(xué)嵌入式開(kāi)發(fā)] 堆和棧

作者: 時(shí)間:2016-11-28 來(lái)源:網(wǎng)絡(luò ) 收藏
堆(heap)和棧(stack)是非常重要的概念,當我們進(jìn)行程序開(kāi)發(fā)時(shí)理解它們非常重要,尤其是對于嵌入式系統開(kāi)發(fā)。比如在嵌入式系統中,任務(wù)的棧通常都很小,可能也就幾K字節。在這種情況下,我們就應當盡可能不要將占用內存大的變量分配在棧上,而是應當分配在堆上;此外,也盡量不要采用遞歸的方式來(lái)設計程序,否則很容易造成棧溢出。

從本質(zhì)上說(shuō),堆和棧都是內存,那么我們只能從概念上對其進(jìn)行區分了。為了方便說(shuō)明,現在假設嵌入式軟件是一個(gè)單體程序(這一術(shù)語(yǔ)并不是嵌入式系統開(kāi)發(fā)中的專(zhuān)用術(shù)語(yǔ),是我為了方便說(shuō)明而使用的),也就是操作系統和我們的應用程序是被編譯在同一個(gè)可執行程序當中的,比如,來(lái)自WindRiver的VxWorks就是采用這種方式的。我們知道一個(gè)可執行程序存在最為重要的三個(gè)段。.text段用于存放程序的代碼,即放的是處理器的運行指令。.data用于存放初始化好的數據,當boot loader(請參見(jiàn)《什么是boot loader》)加載程序文件時(shí),會(huì )將程序文件中的.data段拷貝到內存的VMA(Virtual Memory Address,在《熟悉binutils工具集》中有所提及,在嵌入式系統中絕大部分不用虛擬內存,因此,VMA就是實(shí)地址)處,從而完成變量的初始化操作。雖然,我們在C/C++程序中是對全局變量一個(gè)一個(gè)初始化的,但實(shí)際上boot loader是對所有的全局變量通過(guò)將程序文件中的.data段拷貝到內存中一次性的完成初始化的。.bss段用于存放沒(méi)有初始化好的變量,程序文件中并不存放.bss段的具體內容,只是存有.bss段的起始地址和大小,當boot loader加載我們的嵌入式程序文件時(shí),只是根據程序文件中的.bss信息對內存中的.bss塊進(jìn)行清零操作。

圖 1示例了boot loader與我們的單體程序共存的一個(gè)內存和FLASH映射快照。其中我們假設內存的大小是8M字節??梢钥闯鲈贔LASH上即存放了boot loader程序,又存放了我們的單體程序,至于FLASH上是否有文件系統我們在此并不用關(guān)心。在內存中你可以看出也存在一塊boot loader區,這一塊區是由FLASH中的boot loader將自己加載到內存中的,以便加快運行速度,可以想像這塊內存區是最早被拷貝到內存中的。當內存中的boot loader運行時(shí),其會(huì )讀取FLASH中的單體程序,這一單體程序通常是ELF格式的。其中的ELF頭指示了各段的VMA地址和大小以及各段內容在單體程序中的偏移地址。boot loader通過(guò)ELF頭信息,將.texe段和.data段從FLASH拷貝到內存中。顯然,boot loader和單體程序在內存中所占用的地址空間是不能重疊的,否則當boot loader將單體程序從FLASH拷貝到內存時(shí),會(huì )將其自身的內容給覆蓋掉,從而造成自己無(wú)法正常運行。地址的規劃是我們設計boot loader時(shí)需要考慮到的。圖中我們只示例了一個(gè)中斷向量表,其實(shí),很有可能boot loader內存區也有一個(gè)中斷向量表,是供boot loader運行時(shí)用的。還有就是有一塊臨時(shí)的??臻g,這一空間可以是boot loader和單體程序共同使用的,對于共同使用,需要強調的是boot loader與單體程序并不會(huì )同時(shí)運行,當boot loader運行完了以后,會(huì )調轉到單體程序的入口處開(kāi)始運行,入口地址顯然應當位于內存的.text段。而單體程序在一開(kāi)始運行時(shí)(此時(shí)操作系統還沒(méi)有起作用),仍是需要一塊小的內存作為棧來(lái)使用,以便能進(jìn)行函數調用。根據不同的設計,我們可以在單體程序運行的初始階段使用與boot loader相同的棧,當然也可以使用不同的棧。這里我們假設使用相同的棧。從圖1中,我們可以看出,內存中還存在很大的一塊閑置區,這一塊區暫時(shí)還沒(méi)有使用用途。

圖 1
一旦boot loader運行了我們的單體程序,我們說(shuō)boot loader就不存在了,那此時(shí)boot loader所占用的內存空間也就釋放出來(lái)了,如圖 2所示。從圖中可以看出內存中的閑置空間加大了。那閑置空間被我們的單體程序用來(lái)做什么呢?做堆!在單體程序中的操作系統部分,會(huì )提供一定的管理模塊來(lái)管理這塊堆,并提供API(Application Programming Interface,應用程序編程接口)讓我們調用,從而實(shí)現從堆中分配或是釋放內存,這些API類(lèi)似于C語(yǔ)言中的malloc ()/free ()。堆在管理上有一個(gè)特點(diǎn),從堆中分配出來(lái)的內存應當是以某一大小字節為邊界的。比如,如果CPU中的double類(lèi)型是占用內存最多的數據類(lèi)型且是8字節,那么堆分配出來(lái)的內存就必須保證是以8字節為邊界的。這一點(diǎn)請讀者想一想為什么?除了采用動(dòng)態(tài)的內存分配,在嵌入式系統中通常還會(huì )采用固定大小內存塊的分配方法,這種分配方法的好處是非常的快,而且這種內存在使用的過(guò)程中不會(huì )產(chǎn)生內存碎片。

圖 2
堆我們說(shuō)過(guò)了,那接下來(lái)我們看一看如果我們的單體程序繼續運行,會(huì )出現什么樣的內存布局。我們知道,通常我們的單體程序在初始化時(shí)往往需要創(chuàng )建多個(gè)任務(wù)來(lái)實(shí)現其應用功能。對于每一個(gè)任務(wù),它一塊內存是私有的,那就是棧!當任務(wù)運行時(shí),其需要用棧來(lái)做為函數調用時(shí)的參數傳遞空間,以及用棧來(lái)存儲函數內的局部變量。假設我們的單體程序需要創(chuàng )建兩個(gè)任務(wù)A和B,這需要通過(guò)調用操作系統中的任務(wù)創(chuàng )建函數來(lái)達到這一目的。操作系統所提供的任務(wù)創(chuàng )建API往往需要我們指定任務(wù)棧的大小,有的甚至可以指定棧內存空間。一旦任務(wù)創(chuàng )建的API被調用,那么操作系統會(huì )調用堆分配API為任務(wù)分配棧,此時(shí)的內存布局如圖 3所示。任務(wù)創(chuàng )建完了以后,各任務(wù)就可以根據應用程序邏輯的需要審請堆空間以實(shí)現其業(yè)務(wù)邏輯。
上一頁(yè) 1 2 下一頁(yè)

評論


技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>