日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

程序在內(nèi)存中運(yùn)行的奧秘

 skywood 2010-06-21

內(nèi) 存管理是操作系統(tǒng)的核心功能,無(wú)論對(duì)于開(kāi)發(fā)者還是系統(tǒng)管理員內(nèi)存管理的重要性都是不言而喻的。我會(huì)在接下來(lái)的幾篇文章通過(guò)計(jì)算機(jī)的實(shí)際運(yùn)行過(guò)程談?wù)剝?nèi)存管 理,當(dāng)然在必要的時(shí)候我也會(huì)從底層原理去闡釋這個(gè)問(wèn)題。我們提到的概念是不局限于平臺(tái)特性的通用概念,不過(guò)為了闡述這些概念我們選取的實(shí)例大多來(lái)源于Linux和基于x86架構(gòu)的32Windows操作系統(tǒng)。這篇文章,我們首先來(lái)看看程序是如何使用內(nèi)存的。

多任務(wù)操作系統(tǒng)中,每一個(gè)進(jìn)程都有它自己的內(nèi)存“沙盒”。所謂“沙盒”,是指虛擬地址空間,在32位模式下,虛擬地址空間最多能表示4GB容量。通過(guò)頁(yè)表機(jī)制, 虛擬地址空間能夠映射到物理內(nèi)存。頁(yè)表由操作系統(tǒng)內(nèi)核來(lái)管理,并可被處理器訪問(wèn)。每個(gè)進(jìn)程有著屬于自己的頁(yè)表,不過(guò)進(jìn)程也不能隨心所欲。因?yàn)樘摂M地址一旦 投入使用,所有在計(jì)算機(jī)中運(yùn)行的軟件都會(huì)占用虛擬地址空間,包括操作系統(tǒng)內(nèi)核自身。也就是說(shuō),操作系統(tǒng)內(nèi)核將保留一部分虛擬地址空間。

                        

這并不意味著系統(tǒng)內(nèi)核能夠肆無(wú)忌憚的使用物理內(nèi)存,系統(tǒng)內(nèi)核只能使用其管轄的虛擬地址空間所對(duì)應(yīng)的物理內(nèi)存。系統(tǒng)內(nèi)核所使用的內(nèi)存空間通過(guò)特權(quán)碼(privileged code2級(jí)或者更低)來(lái)標(biāo)記,以防止用戶模式的程序訪問(wèn)到內(nèi)核空間而發(fā)生頁(yè)面錯(cuò)誤。在Linux中,內(nèi)核始終占用著一定空間,并且每個(gè)內(nèi)核進(jìn)程映射的物理內(nèi)存地址是固定的。因此,內(nèi)核代碼與數(shù)據(jù)在內(nèi)存中的地址總是能夠被準(zhǔn)確定位,從而為時(shí)刻處理中斷以及系統(tǒng)調(diào)用做好了準(zhǔn)備。與此相反,只要用戶進(jìn)程狀態(tài)發(fā)生變化,其映射的地址空間也隨即改變。

圖中藍(lán)色區(qū)域表示虛擬地址中映射到物理內(nèi)存的部分,白色區(qū)域則是未映射。在這個(gè)例子中,Firefox驚人的內(nèi)存需求讓它使用的虛擬地址遠(yuǎn)遠(yuǎn)超過(guò)了其自身的地址空間。內(nèi)存地址空間是由諸如堆、棧等段式內(nèi)存管理方式進(jìn)行管理的。需要指出的是,這里段的概念只不過(guò)是表示了一段內(nèi)存地址,它和Intel段表機(jī)制(Intel-style segments)沒(méi)有任何關(guān)系??偟膩?lái)說(shuō),我們?cè)谶@里討論的是Linux系統(tǒng)進(jìn)程標(biāo)準(zhǔn)的段式內(nèi)存管理方法。

如 果運(yùn)行過(guò)程輕松愉快、準(zhǔn)確無(wú)誤,那么上圖顯示的段式虛擬地址管理啟用過(guò)程對(duì)于計(jì)算機(jī)內(nèi)幾乎所有進(jìn)程都完全一致。而這種機(jī)制為遠(yuǎn)程攻擊帶來(lái)了安全隱患。遠(yuǎn)程 攻擊往往需要參考絕對(duì)內(nèi)存地址:諸如棧地址、庫(kù)函數(shù)地址等等。而遠(yuǎn)程攻擊者們知道了這些地址空間是固定的,他們閉著眼睛都能找到他們需要的位置。倘若真的 如此,那么人們毫無(wú)疑問(wèn)就會(huì)被黑客攻擊了。正因?yàn)槿绱?,隨即地址空間已經(jīng)成為流行的內(nèi)存地址管理方式。Linux隨機(jī)為棧(stack)、內(nèi)存映射段(memorymapping segment)以及堆(heap )的起始地址添加偏移量。不幸的是,32位地址空間非常吃緊,限制了隨機(jī)分配地址的范圍和效率(hamperingits effectiveness)。

進(jìn)程地址空間的首段地址便是棧,它儲(chǔ)存了局部變量以及大多數(shù)編程語(yǔ)言的函數(shù)參數(shù)。當(dāng)調(diào)用方法或者函數(shù)時(shí),會(huì)有一個(gè)新的元素進(jìn)棧。一旦函數(shù)返回了值,那么該元素就會(huì)被銷毀。這種簡(jiǎn)單的設(shè)計(jì),很有可能是考慮到數(shù)據(jù)操作都符合后進(jìn)先出(LIFO )規(guī)則,這意味著訪問(wèn)棧的內(nèi)容并不需要復(fù)雜的數(shù)據(jù)結(jié)構(gòu),一個(gè)簡(jiǎn)單的棧頂指針就能搞定一切。進(jìn)棧和出棧的操作方便快捷,不需要過(guò)多判斷。另外,棧的反復(fù)使用能夠使棧主流在CPU緩存(cpu caches)中,從而加快數(shù)據(jù)存取。每個(gè)進(jìn)程中的每個(gè)線程都有屬于自己的棧。

如果映射的棧地址空間被壓入了超過(guò)棧容量的數(shù)據(jù),那么棧便無(wú)法繼續(xù)工作了。這種情況會(huì)導(dǎo)致一個(gè)由expand_stack(),函數(shù)處理的頁(yè)面錯(cuò)誤,這個(gè)函數(shù)會(huì)調(diào)用acct_stack_growth() 函數(shù)去檢查是否應(yīng)該為這個(gè)棧增加容量。如果這個(gè)棧的容量低于RLIMIT_STACK (通常為 8MB)限 定的值,那么棧的容量會(huì)正常增加,程序也會(huì)繼續(xù)正常運(yùn)行,并且程序不會(huì)知道剛剛發(fā)生了什么。當(dāng)然,這是根據(jù)實(shí)際需要來(lái)調(diào)整棧大小的一般機(jī)制,如果棧的容量 達(dá)到了最大值上限,那么棧就會(huì)溢出,程序也會(huì)收到一個(gè)段出錯(cuò)的信息。雖然在程序需要的時(shí)候映射的??臻g會(huì)增加,但是棧使用的空間減少時(shí),棧卻不會(huì)釋放多于 的空間。這就好像聯(lián)邦政府預(yù)算,只可能越來(lái)越多。

程序存取上圖所示的未映射區(qū)域,是唯一正常實(shí)現(xiàn)動(dòng)態(tài)增加??臻g的情況,程序訪問(wèn)其他未映射內(nèi)存訪問(wèn)將會(huì)出現(xiàn)頁(yè)面錯(cuò)誤最終導(dǎo)致段錯(cuò)誤。有些映射區(qū)域是只讀的,程序試圖寫入這些區(qū)域同樣會(huì)導(dǎo)致這種錯(cuò)誤。

說(shuō)到堆,我們就不得不提它的內(nèi)存使用機(jī)制。堆支持運(yùn)行時(shí)內(nèi)存分配,和棧不同,大多數(shù)語(yǔ)言都允許程序使用堆管理內(nèi)存。滿足內(nèi)存需求是語(yǔ)言運(yùn)行時(shí)和C語(yǔ)言核心間的聯(lián)結(jié)點(diǎn),而堆的內(nèi)存管理接口是通過(guò)malloc()及其友元函數(shù)來(lái)實(shí)現(xiàn)的,在C#這樣支持垃圾回收機(jī)制的語(yǔ)言中,其接口是新定義的關(guān)鍵字。

當(dāng)堆的空間能夠滿足程序的內(nèi)存請(qǐng)求時(shí),那么請(qǐng)求的處理過(guò)程就可以直接由語(yǔ)言運(yùn)行時(shí)來(lái)負(fù)責(zé),而不必有系統(tǒng)內(nèi)核參與。但是如果堆的空間不能滿足程序的內(nèi)存申請(qǐng),那么brk()函數(shù)會(huì)執(zhí)行系統(tǒng)調(diào)用(implementation)來(lái)增加堆得內(nèi)存空間以滿足程序的請(qǐng)求。堆管理的實(shí)現(xiàn)過(guò)程十分復(fù)雜,,面對(duì)程序內(nèi)存分配變化莫測(cè)的情況,堆管理需要成熟的算法去提升請(qǐng)求的響應(yīng)速度與內(nèi)存利用率。系統(tǒng)響應(yīng)堆的內(nèi)存請(qǐng)求花費(fèi)的時(shí)間往往變化很大。實(shí)時(shí)操作系統(tǒng)解決這個(gè)問(wèn)題的方法是采用專用內(nèi)存分配器( special-purposeal locators)。堆在內(nèi)存中的分布情況和其他內(nèi)存管理管理機(jī)制一樣充滿了碎片,如下圖所示:


最后,我們來(lái)聊聊剛才圖中位置最下方的幾個(gè)內(nèi)存段:BSS段、數(shù)據(jù)段和程序段。在C語(yǔ)言中,BSS段和數(shù)據(jù)段存儲(chǔ)的都是靜態(tài)(全局)變量。這幾個(gè)段的不同之處在于BSS段存儲(chǔ)的靜態(tài)變量沒(méi)有初始化——程序員在源代碼中并沒(méi)有為這些靜態(tài)變量賦值。由于BSS段并沒(méi)有映射任何文件,所以BSS段在內(nèi)存中是以匿名形式存在的。舉個(gè)例子,假設(shè)你定義了變量static int cntActiveUsers,那么cntActiveUsers 的數(shù)據(jù)就保存在BSS段中。

BSS段不同的是,數(shù)據(jù)段儲(chǔ)存了在源代碼中經(jīng)過(guò)了初始化的靜態(tài)變量。因此,數(shù)據(jù)段的內(nèi)存區(qū)域并不是匿名的。數(shù)據(jù)段映射了程序二進(jìn)制映像中源代碼給出靜態(tài)變量初值的部分。所以,如果你定義了static int cntWorkerBees = 10,那么cntWorkerBees變量會(huì)賦以初值10并在數(shù)據(jù)段中保存下來(lái)。盡管數(shù)據(jù)段映射了文件,但這種內(nèi)存映射是私有的,也就是說(shuō),數(shù)據(jù)段的內(nèi)存更新不會(huì)在其映射的文件中生效。這樣造成的結(jié)果就是,雖然全局變量的改變應(yīng)用到了文件在內(nèi)存中的二進(jìn)制映像,但是文件本身卻不能作出相應(yīng)的變化!

下面圖表中的示例由于使用了指針?biāo)钥雌饋?lái)不那么明了。在這個(gè)示例中,指針在數(shù)據(jù)段中占用了4個(gè)字節(jié),但是指針?biāo)赶虻淖址畡t不在數(shù)據(jù)段中。對(duì)于字符串,內(nèi)存為它們準(zhǔn)備了專門的文本段,文本段以只讀的形式存儲(chǔ)程序中諸如字符串類型等不會(huì)被直接執(zhí)行的代碼。文本段同樣會(huì)將二進(jìn)制文件映射到內(nèi)存,但文件映射區(qū)域的寫入操作只能以程序收到段錯(cuò)誤而告終。這種機(jī)制能有效防止指針的錯(cuò)誤指向?qū)е碌恼`操作,不過(guò)也不得不承認(rèn)這種做法顯然沒(méi)有直接在C語(yǔ)言代碼中進(jìn)行保護(hù)來(lái)的效率高。下面的圖表顯示了剛剛我們討論到的段以及變量示例:

如果你想了解Linux中的進(jìn)程是如何使用內(nèi)存的,你可以讀讀源代碼文件/proc/pid_of_process/maps。值得一提的是,一個(gè)內(nèi)存段往往由多個(gè)區(qū)域組成。例如,每個(gè)正確映射到內(nèi)存的文件都有屬于自己的段,動(dòng)態(tài)庫(kù)文件則擁有另外的段,這些段類似于BSS段與數(shù)據(jù)段。下一篇文章我們將進(jìn)一步探討“區(qū)域”的含義。另外,也會(huì)談?wù)勎覀€(gè)人對(duì)“數(shù)據(jù)段就是數(shù)據(jù)、BSS以及堆的總和”這種觀點(diǎn)的看法。

使用nm  objdump命令能夠顯示二進(jìn)制映像的標(biāo)識(shí),映像的地址、段等等信息都可以查閱。最后要指出的是,上文討論的Linux虛擬地址管理機(jī)制是“靈活”的,該機(jī)制在Linux中作為首選已經(jīng)沿用了幾年。使用這種機(jī)制要求程序?yàn)?/span>RLIMIT_STACK變量賦值,如果沒(méi)有,那么Linux則退回到“傳統(tǒng)”方式管理內(nèi)存,如下圖所示:


該圖呈現(xiàn)了虛擬地址空間的管理方式。下一篇文章我們將討論系統(tǒng)內(nèi)核是如何跟蹤這些內(nèi)存區(qū)域的。進(jìn)而我們會(huì)看看內(nèi)存映射原理、與之相關(guān)的文件讀寫機(jī)制以及內(nèi)存使用情況圖表所揭示的含義。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多