資源描述:
《windows內(nèi)存機(jī)制解析》由會員上傳分享,免費在線閱讀,更多相關(guān)內(nèi)容在行業(yè)資料-天天文庫。
1、Windows內(nèi)存機(jī)制解析Byleezy_200003-9-39:38前言?寫這篇文章之前相當(dāng)長的一段時間里,對windows內(nèi)存機(jī)制是有著相當(dāng)?shù)睦Щ蟮摹8鱾€進(jìn)程的內(nèi)存空間是如何隔離和共享的?GDT(全局描述表)尚在,可分段機(jī)制去了那里?既然我們有虛擬的4G空間和結(jié)構(gòu)化異常為何分配內(nèi)存仍可能失???在什么時候stack會溢出?―――當(dāng)我把這些問題都弄清楚后,我寫了這篇文章為自己做了個總結(jié),希望對大家也有幫助。同時由于寫Windows內(nèi)存這塊的文章比較多,我將盡力做到與別人的內(nèi)容不重合。動筆后不久,我發(fā)現(xiàn)imquestion對于W
2、indows內(nèi)存寫了幾篇非常不錯的文章,總題目叫《JIURL玩玩Win2k內(nèi)存篇》,推薦閱讀。?一、總論?Windows內(nèi)存管理機(jī)制,底層最核心的東西是分頁機(jī)制。分頁機(jī)制使每個進(jìn)程有自己的4G虛擬空間,使我們可以用虛擬線性地址來跑程序。每個進(jìn)程有自己的工作集,工作集中的數(shù)據(jù)可以指明虛擬線性地址對應(yīng)到怎樣的物理地址。進(jìn)程切換的過程也就是工作集切換的過程,如MattPietrek所說如果只給出虛擬地址而不給出工作集,那這個地址是無意義的。(見圖一)?在分頁機(jī)制所形成的線性地址空間里,我們對內(nèi)存進(jìn)行進(jìn)一步劃分涉及的概念有堆、棧、自由
3、存儲等。對堆進(jìn)行操作的API有HeapCreate、HeapAlloc等。操縱自由存儲的API有VirtualAlloc等。此外內(nèi)存映射文件使用的也應(yīng)該算是自由存儲的空間。棧則用來存放函數(shù)參數(shù)和局部變量,隨著stackframe的建立和銷毀其自動進(jìn)行增長和縮減。?說到這里,也許有人會提出疑問:對x86CPU分段機(jī)制是必須的,分頁機(jī)制是可選的。為什么這里只提到了分頁機(jī)制。那么我告訴你分段機(jī)制仍然存在,一是為了兼容以前的16位程序,二是Windows畢竟要區(qū)分ring0和ring3兩個特權(quán)級。用SoftIce看一下GDT(全局描述
4、表)你基本上會看到如下內(nèi)容:?GDTbase=80036000Limit=03FF?0008Code32Base=00000000Lim=FFFFFFFFDPL=0PRE?//內(nèi)核態(tài)driver代碼段?0010Data32Base=00000000Lim=FFFFFFFFDPL=0PRW//內(nèi)核態(tài)driver的數(shù)據(jù)段?001BCode32Base=00000000Lim=FFFFFFFFDPL=3PRE//應(yīng)用程序的代碼段?0023Data32Base=00000000Lim=FFFFFFFFDPL=3PRW//應(yīng)用程序的數(shù)據(jù)
5、段?這意味著什么呢??我們再看一下線性地址的生成過程(見圖一)。從中我們應(yīng)該可以得出結(jié)論,如果segmengbaseaddress為0的話,那么這個段可以看作不存在,因為偏移地址就是最終的線性地址。?此外還有兩個段存在用于KernelProcessorControlRegion和userthreadenvironmentblock。所以如果你在反匯編時看到MOVECX,FS:[2C]就不必驚訝,怎么這里使用邏輯地址而不是線性地址。在以后涉及異常處理的地方會對此再做說明。??二、從Stack說開去?從我個人的經(jīng)驗看,談到內(nèi)存時說
6、堆的文章最多,說stack的最少。我這里反其道而行的原因是stack其實要比堆更重要,可以有不使用堆的程序,但你不可能不使用stack,雖然由于對stack的管理是由編譯器確定了的,進(jìn)而他較少出錯。?通過鏈接開關(guān)/STACK:reserve[,commit]可以指定進(jìn)程主線程的stack大小,當(dāng)你建立其他線程時如果不指定dwStackSize參數(shù),則也將使用/STACK所指定的值。微軟說,如果指定較大的commit值將有利于提升程序的速度,我沒驗證過,但理應(yīng)如此。通常并不需要對STACK進(jìn)行什么設(shè)定,缺省的情況下將保留1M空間
7、,并提交兩個頁(8Kforx86)。而1M空間對于大多數(shù)程序而言是足夠的,但為防止stackoverflow有三點需要指出一是當(dāng)需要非常大的空間時最好用全局?jǐn)?shù)組或用VirtualAlloc進(jìn)行分配,二是引用傳遞或用指針傳遞尺寸較大的函數(shù)參數(shù)(這點恐怕地球人都知道),三是進(jìn)行深度遞歸時一定要考慮會不會產(chǎn)生stack溢出,如果有可能,可以采用我在《遞歸與goto》一文中提到的辦法來仿真遞歸,這時候可以使用堆或自由存儲來代替stack。同時結(jié)構(gòu)化異常被用來控制是否為stack提交新的頁面。(這部分寫的比較簡略因為很多人都寫過,推薦閱
8、讀JefferyRitcher《Windows核心編程》第16章)?下面我們來看一下stack的使用。假設(shè)我們有這樣一個簡單之極的函數(shù):??int__stdcalladd_s(intx,inty){intsum;?sum=x+y;?returnsum;}?這樣在調(diào)用函數(shù)前,通