《電子技術(shù)應(yīng)用》
您所在的位置:首頁(yè) > 嵌入式技術(shù) > 設(shè)計(jì)應(yīng)用 > WinCE線(xiàn)程和內(nèi)存管理之內(nèi)存管理
WinCE線(xiàn)程和內(nèi)存管理之內(nèi)存管理
互聯(lián)網(wǎng)
摘要: 同其它Windows操作系統(tǒng)一樣,Windows CE.NET也支持32位虛擬內(nèi)存機(jī)制、按需分配內(nèi)存和內(nèi)存映射文件等。但是與其它Windows操作系統(tǒng)又有明顯的不同。
Abstract:
Key words :
內(nèi)存管理

  同其它Windows操作系統(tǒng)一樣,Windows CE.NET也支持32位虛擬內(nèi)存機(jī)制、按需分配內(nèi)存和內(nèi)存映射文件等。但是與其它Windows操作系統(tǒng)又有明顯的不同。 
 
<a class=WinCE線(xiàn)程和內(nèi)存管理之內(nèi)存管理圖片2" height="1" width="1" />       畢竟Windows CE是一種嵌入式實(shí)時(shí)性的操作系統(tǒng),在內(nèi)存管理方面必須要比其它Windows操作系統(tǒng)更節(jié)約物理內(nèi)存和虛擬地址空間。在內(nèi)存管理API方面,為了便于移植程序,Windows CE和其它Windows操作系統(tǒng)函數(shù)聲明基本一致,這使一個(gè)在其它Windows下開(kāi)發(fā)的程序員可以直接使用早就熟悉的API函數(shù), 但是CE下內(nèi)存管理的原理開(kāi)發(fā)者還是應(yīng)該熟悉的。

  1、ROM和RAM

  對(duì)于早期采用的存儲(chǔ)設(shè)備一般采用ROM + RAM ,在ROM中存放的所有文件可以是壓縮的也可以是不壓縮的,這取決于OEM(原始設(shè)備制造商)。OEM在定制CE內(nèi)核時(shí)可以設(shè)置一個(gè)標(biāo)志告訴ROM鏡像制作工具(romimage.exe)是否壓縮文件。對(duì)于ROM中存放的模塊(DLL、EXE文件)來(lái)說(shuō),如果是壓縮的,模塊在運(yùn)行前先解壓并全部存放到RAM中。如果是不壓縮的,并且ROM介質(zhì)支持線(xiàn)性訪問(wèn)(line-Accessed),就可以本地執(zhí)行(executed in place,縮寫(xiě)為XIP)。利用本地執(zhí)行方式運(yùn)行應(yīng)用程序、DLL的優(yōu)點(diǎn)是:采用這種技術(shù)在加載EXE或DLL時(shí),其中的代碼段數(shù)據(jù)不加載到物理內(nèi)存中,內(nèi)核只是分配虛擬地址空間給代碼段,當(dāng)執(zhí)行代碼時(shí)內(nèi)核會(huì)到實(shí)際存放在ROM存儲(chǔ)設(shè)備上的文件中尋找代碼并執(zhí)行。采用這樣的技術(shù)既可以節(jié)省可用內(nèi)存又可以減少加載的時(shí)間。但是這種技術(shù)有一定的局限性,如果要讓CPU到ROM中去尋找代碼執(zhí)行,那么ROM介質(zhì)必須支持線(xiàn)性訪問(wèn),這就要求ROM介質(zhì)支持線(xiàn)性訪問(wèn),而不是塊訪問(wèn)。XIP這種加載方式的缺點(diǎn)就是執(zhí)行速度相對(duì)較慢,CPU訪問(wèn)ROM的速度肯定遠(yuǎn)慢于訪問(wèn)RAM的速度。
 
  基于Windows CE的產(chǎn)品開(kāi)始采用FLASH、IDE等永久存儲(chǔ)設(shè)備時(shí),內(nèi)核鏡像(.bin)和其它應(yīng)用程序文件開(kāi)始存放到永久存儲(chǔ)設(shè)備中而不是ROM中,這不僅僅是因?yàn)橛脖P(pán)或者FLASH的I/O速度比ROM快,更因?yàn)楝F(xiàn)在的內(nèi)核包含的功能多并且文件數(shù)量增加,因而需要的存儲(chǔ)空間很大,一般都在20MB左右。再加上其它開(kāi)發(fā)商開(kāi)發(fā)的應(yīng)用程序文件,要求的空間就更大了。CE啟動(dòng)時(shí)內(nèi)核鏡像由加載程序解壓并將系統(tǒng)文件加載到RAM的NK,NK是在config.bib中定義的一段RAM區(qū)域,專(zhuān)用于保存內(nèi)核鏡像解壓出來(lái)的所有文件。Windows CE將NK看作是ROM,當(dāng)執(zhí)行一個(gè)應(yīng)用程序時(shí),CE內(nèi)核將這個(gè)應(yīng)用程序需要的系統(tǒng)DLL(在NK中保存)加載到Slot 1(地址范圍0x0200 0000-0x03FF FFFF,在Windows CE.NET中Slot 1專(zhuān)用于XIP DLL使用)。Slot 1是一段虛擬地址,當(dāng)CPU執(zhí)行DLL的代碼時(shí),CPU會(huì)根據(jù)地址映射關(guān)系到NK中尋找實(shí)際的代碼執(zhí)行,因?yàn)镹K是一段實(shí)際的物理內(nèi)存,I/O速度非???,所以相對(duì)于在ROM中執(zhí)行,DLL的運(yùn)行效率得到很大提高。

  非XIP DLL在加載時(shí)CE內(nèi)核會(huì)在調(diào)用DLL的進(jìn)程的地址空間中申請(qǐng)足夠大的地址空間,并且執(zhí)行代碼時(shí)按需提交物理內(nèi)存。

  RAM和ROM文件系統(tǒng)是Windows CE默認(rèn)的文件系統(tǒng)。RAM文件系統(tǒng)的優(yōu)點(diǎn)是支持文件壓縮、支持事務(wù)機(jī)制(和數(shù)據(jù)庫(kù)中的事務(wù)機(jī)制相似)、數(shù)據(jù)I/O較快。Windows CE.NET啟動(dòng)時(shí)把除了NK以外的RAM分為對(duì)象存儲(chǔ)(object store)區(qū)域和應(yīng)用程序內(nèi)存(program memory)區(qū)域,并且默認(rèn)各使用一半RAM。在基于Windows CE的設(shè)備沒(méi)有采用永久存儲(chǔ)器之前,對(duì)象存儲(chǔ)的作用相當(dāng)于永久存儲(chǔ)器,對(duì)象存儲(chǔ)區(qū)域采用RAM文件系統(tǒng)來(lái)保存文件,對(duì)象存儲(chǔ)中可以存儲(chǔ)的對(duì)象類(lèi)型有文件、目錄、數(shù)據(jù)庫(kù)、記錄、數(shù)據(jù)庫(kù)卷。默認(rèn)在對(duì)象存儲(chǔ)中存儲(chǔ)的對(duì)象全部是壓縮的。當(dāng)整個(gè)系統(tǒng)關(guān)閉時(shí),設(shè)備的電源還繼續(xù)提供電力給RAM,這樣對(duì)象存儲(chǔ)中保存的所有數(shù)據(jù)就不會(huì)丟失。應(yīng)用程序內(nèi)存區(qū)域留給所有應(yīng)用程序運(yùn)行時(shí)使用?;赪indows CE的設(shè)備采用永久存儲(chǔ)器后,對(duì)象存儲(chǔ)的作用就被永久存儲(chǔ)器替代了,所以采用永久存儲(chǔ)器后,應(yīng)該減小對(duì)象存儲(chǔ)區(qū)域的大小。如果定制的Windows CE的內(nèi)核包含了資源管理器(eXPlorer.exe),那么打開(kāi)“控制面板”,在“系統(tǒng)”-“內(nèi)存”中,可以調(diào)節(jié)這兩個(gè)存儲(chǔ)區(qū)域的比例?;瑝K向左,則釋放對(duì)象存儲(chǔ)區(qū)域的一些可用內(nèi)存并將這些內(nèi)存劃到應(yīng)用程序內(nèi)存區(qū)域中?;瑝K向右則相反。

  2、內(nèi)存結(jié)構(gòu)

  Windows CE.NET只能管理512MB的物理內(nèi)存和4GB大小的虛擬地址空間。不同的CPU內(nèi)存管理方法也不同。對(duì)于MIPS和SHX系列CPU來(lái)說(shuō),物理地址映射是由CPU完成的,CE內(nèi)核可以直接訪問(wèn)512MB的物理內(nèi)存。對(duì)于x86系列和ARM系列的CPU來(lái)說(shuō),在內(nèi)核啟動(dòng)過(guò)程中它會(huì)將現(xiàn)有物理內(nèi)存地址全部映射到0x8000 0000以上的虛擬地址空間中供內(nèi)核以后使用。OEM可以通過(guò)OEMAddressTable來(lái)詳細(xì)定義虛擬地址和物理地址的映射關(guān)系。OEMAddressTable本身并不是一個(gè)文件,它只是存在于其它文件中描述虛擬地址和實(shí)際物理地址的映射關(guān)系的數(shù)據(jù)。比如文件oem init.asm中包含一段代碼:dd 80000000h, 0, 04000000h 。它表示將整個(gè)物理地址(0x0400 0000=64MB)共64MB映射到虛擬地址從0x8000 0000到0x8400 0000中。關(guān)于OEMAddressTable我將在以后關(guān)于PB的文章中講述。

  整個(gè)4GB虛擬地址空間主要?jiǎng)澐譃閮刹糠?,?x8000 0000以上為內(nèi)核使用部分,0x8000 0000以下為應(yīng)用程序使用部分。詳細(xì)見(jiàn)下表:

地址范圍用途 0x0000 0000到0x41FF FFFF   由所有應(yīng)用程序使用。共33個(gè)槽,每個(gè)槽占32MB。槽0(Slot 0)由當(dāng)前占有CPU的進(jìn)程使用。槽1由XIP DLL使用。其它槽用于進(jìn)程使用,每個(gè)進(jìn)程占用一個(gè)槽。 0x4200 0000到0x7FFF FFFF   由所有應(yīng)用程序共享的區(qū)域。32MB地址空間有時(shí)不能夠滿(mǎn)足一些進(jìn)程的需求。那么進(jìn)程可以使用這個(gè)范圍的地址空間。在這個(gè)區(qū)域里應(yīng)用程序可以建堆、創(chuàng)建內(nèi)存映射文件、分配大的地址空間等。 0xA000 0000到0xBFFF FFFF   在這個(gè)范圍內(nèi)核重復(fù)定義0x8000 0000到0x9FFF FFFF之間定義的物理地址映射空間。區(qū)別是在這范圍映射的虛擬地址空間不能夠用于緩沖。

  我舉例來(lái)說(shuō)明:假設(shè)一個(gè)產(chǎn)品有64MB物理內(nèi)存。如上文所述定義好OEMAddressTable后。內(nèi)核啟動(dòng)后一個(gè)物理地址映射空間范圍在0x8000 0000到0x8400 0000,那么內(nèi)核會(huì)從0xA000 0000到0xA400 0000定義一個(gè)同樣范圍的地址空間,這個(gè)地址空間和0x8000 0000到0x8400 0000映射到相同的物理地址。但這個(gè)虛擬地址空間不能夠用于緩沖。 0xC000 0000到0xC1FF FFFF 系統(tǒng)保留空間 0xC200 0000到0xC3FF FFFF 內(nèi)核程序nk.exe使用的地址空間。 0xC400 0000到0xDFFF FFFF   這個(gè)范圍為用戶(hù)定義的靜態(tài)虛擬地址空間,但這個(gè)地址空間只能用于非緩沖使用。
  利用OEMAddressTable定義物理地址映射空間后,每次內(nèi)核啟動(dòng)時(shí)這個(gè)范圍都不改變了,除非產(chǎn)品包含的物理內(nèi)存容量發(fā)生變化。假如增加到128MB物理內(nèi)存,那么物理地址映射空間也向后擴(kuò)大了一倍。Windows CE.NET也允許用戶(hù)創(chuàng)建靜態(tài)的物理地址映射空間。用戶(hù)可以調(diào)用CreateStaticMapping函數(shù)或者NKCreateStaticMapping函數(shù)來(lái)映射某一段物理地址到0xC400 0000和0xE000 0000之間的某一個(gè)范圍。需要注意的是用這個(gè)函數(shù)創(chuàng)建的靜態(tài)虛擬地址只能夠由內(nèi)核訪問(wèn),而且不能用于緩沖。

0xE000 0000到0xFFFF FFFF 內(nèi)核使用的虛擬地址。當(dāng)內(nèi)核需要大的虛擬地址空間時(shí),會(huì)在這個(gè)范圍內(nèi)分配。    

WinCE線(xiàn)程和內(nèi)存管理之內(nèi)存管理圖片9
圖1 Windows CE.NET內(nèi)存結(jié)構(gòu)

進(jìn)入討論組討論。


  3、進(jìn)程地址空間結(jié)構(gòu)

  進(jìn)程地址空間結(jié)構(gòu)如圖2所示。這個(gè)圖源至MSDN。 
 WinCE線(xiàn)程和內(nèi)存管理之內(nèi)存管理圖片2
        WinCE線(xiàn)程和內(nèi)存管理之內(nèi)存管理圖片2Windows CE.NET同以前版本的Windows CE操作系統(tǒng)在進(jìn)程地址空間上有所不同,以前的Windows CE把XIP DLL也加載到進(jìn)程的32MB地址空間中,而Windows CE.NET把XIP DLL單獨(dú)加載到Slot 1中,這樣對(duì)于每個(gè)進(jìn)程來(lái)說(shuō),它總的地址空間就大了一倍,也就是64MB。這個(gè)問(wèn)題我在講解進(jìn)程的時(shí)候提到過(guò)。

  當(dāng)一個(gè)應(yīng)用程序啟動(dòng)時(shí),內(nèi)核為這個(gè)程序選擇一個(gè)空閑的槽(Slot),并且加載所有的代碼、資源,并分配堆棧,加載DLL等。當(dāng)這個(gè)進(jìn)程得到CPU使用權(quán)時(shí),它的整個(gè)地址空間被內(nèi)核映射到Slot 0,也就是當(dāng)前進(jìn)程使用的地址空間,然后開(kāi)始運(yùn)行。圖中給出的地址實(shí)際上是經(jīng)過(guò)映射到Slot 0之后的結(jié)構(gòu)。從圖中可以看出,進(jìn)程首先加載代碼段,因?yàn)槊總€(gè)進(jìn)程最低部64KB作為保留區(qū)域,所以代碼段從0x0001 0000開(kāi)始,內(nèi)核為代碼段分配足夠的虛擬地址空間后,接著分配空間為只讀數(shù)據(jù)和可讀/可寫(xiě)數(shù)據(jù),接著分配空間為資源數(shù)據(jù),之后分配空間為默認(rèn)堆和棧。非XIP DLL從進(jìn)程最高地址向下開(kāi)始加載。非XIP DLL的加載按如下規(guī)則:內(nèi)核先檢查要加載的DLL是否被其它進(jìn)程加載過(guò),如果加載過(guò),就做一個(gè)地址的重定位。這樣就避免了整個(gè)系統(tǒng)內(nèi)多次加載相同DLL。如果沒(méi)有加載過(guò),就按照從槽的高地址到槽的低地址的順序查找空閑的地址空間。然后分配足夠的地址空間用于加載DLL。因?yàn)槊總€(gè)進(jìn)程在執(zhí)行前都要映射到Slot 0,而且進(jìn)程使用的所有DLL可能來(lái)自不同的槽(Slot),為避免所有使用的DLL在映射到Slot 0中出現(xiàn)地址空間沖突的現(xiàn)象,內(nèi)核的加載器(Loader)在加載DLL時(shí)會(huì)查找所有槽中加載的DLL的地址,保證在映射到Slot 0時(shí)不會(huì)發(fā)生地址沖突現(xiàn)象。假如系統(tǒng)內(nèi)有兩個(gè)進(jìn)程,進(jìn)程A只加載了DLL A,進(jìn)程B
此內(nèi)容為AET網(wǎng)站原創(chuàng),未經(jīng)授權(quán)禁止轉(zhuǎn)載。