用自己照片做衣服 杯子的是哪個網(wǎng)站aso排名
目錄
預備知識
進程地址空間
什么是進程地址空間
為什么要存在進程地址空間和頁表
缺頁中斷
預備知識
我們在學習語言的時候,一般都會了解到內(nèi)存區(qū)域劃分,下面了解一下Linux的內(nèi)存區(qū)域劃分。
?通過上圖,我們了解到
1、堆區(qū)向上增長,棧區(qū)向下增長。
2、環(huán)境變量和命令行參數(shù),無論是表還是內(nèi)容,都在棧區(qū)的上面。
3、先有命令行參數(shù)表,再有環(huán)境變量。
在Linux中,每次打印的地址都一樣,windows每次訪問地址都是隨機的。而Linux是一樣的。
靜態(tài)變量只初始化一次(默認初始化)并不隨函數(shù)的調(diào)用而釋放,一般在初始化數(shù)據(jù)區(qū)域中。
從系統(tǒng)的角度來看,語言中定義的靜態(tài)變量(不論是全局還是局部)已經(jīng)是全局變量了,只是局部的靜態(tài)變量受到作用域限制,本質(zhì)上程序運行期間一直存在的,因為程序運行期間,代碼和數(shù)據(jù)會一直伴隨著。
進程地址空間
我們來看一個現(xiàn)象:
同一個地址,通過不同進程去訪問得到兩個不同的值。
說明這個地址是虛擬地址(線性地址)而非物理地址。
編程語言中的地址都是虛擬地址。
我們在學習語言時了解到的內(nèi)存分區(qū)實際上不是內(nèi)存,而是進程地址空間。
每一個進程都要有進程地址空間。
程序變?yōu)檫M程后,每一個進程都有進程地址空間,與語言無關。所有編譯型語言都必須符合此規(guī)則(每個進程都要有進程地址空間)。
首先,我們解決一下這個問題:
通過研究發(fā)現(xiàn),每一個進程在創(chuàng)建的時候,操作系統(tǒng)都要為其維護一個專屬的進程地址空間,再通過一種哈希映射的思想維護一張表,用來將操作系統(tǒng)從進程處拿到的虛擬地址轉(zhuǎn)化為物理地址,再通過物理地址去訪問數(shù)據(jù)。
這樣的設計方式,也可以解釋為什么fork創(chuàng)建子進程后,為什么返回值可以讓父子進程不同,本質(zhì)是父子進程各自的映射表中,將同一個虛擬地址映射到兩個不同的物理內(nèi)存中去。
進程=task_struct+代碼和數(shù)據(jù)
task_struct是每個進程獨有的,代碼是只讀的,數(shù)據(jù)修改時可以寫時拷貝,所以,進程是獨立的。
什么是進程地址空間
進程地址空間本質(zhì)就是特定的內(nèi)核數(shù)據(jù)結構對象。
每一個進程都會擁有一個進程地址空間。
在32位操作系統(tǒng)下,進程地址空間的大小是[0,4GB]。
操作系統(tǒng)通過"先描述,再組織"的方式管理進程的地址空間。
進程地址空間本質(zhì)就是數(shù)據(jù)結構節(jié)點,Linux中此節(jié)點名稱為mm_struct。
mm_struct中記錄該進程地址空間的字段,通過這些字段來做區(qū)域劃分,管理每個區(qū)域的變化。
區(qū)域內(nèi)的各個地址空間都可以使用。
代碼和數(shù)據(jù)都存儲在物理內(nèi)存中,進程地址空間中的都是虛擬地址。
上述圖中的哈希映射表稱之為頁表。
一個程序要運行時,首先創(chuàng)建PCB,處理好PCB內(nèi)部信息,比如pid、優(yōu)先級、進程地址空間。然后將代碼和數(shù)據(jù)加載到內(nèi)存中,操作系統(tǒng)要訪問數(shù)據(jù)時,通過該進程的進程地址空間拿到虛擬地址,利用頁表將虛擬地址轉(zhuǎn)化為物理地址,通過物理地址拿到數(shù)據(jù)。
其中,CPU內(nèi)部的CR3寄存器存儲頁表的物理地址,MMU硬件單元管理著整個映射地址、轉(zhuǎn)換地址的工作。
為什么要存在進程地址空間和頁表
1、將物理內(nèi)存從無序變?yōu)橛行?#xff0c;讓進程以統(tǒng)一的視角看待內(nèi)存。
2、將進程管理和內(nèi)存管理解耦合
3、進程地址空間和頁表組合的設計是保護內(nèi)存安全的重要手段。
磁盤將可執(zhí)行程序加載到內(nèi)存中數(shù)據(jù)是不連續(xù)的。如果操作系統(tǒng)直接管理不連續(xù)的物理地址效率很低。所以我們將這個程序?qū)摫淼奶摂M地址設計成連續(xù)的,連續(xù)的虛擬地址映射到不連續(xù)的物理地址上,進程管理與內(nèi)存管理之間沒有關系,操作系統(tǒng)通過頁表將虛擬-物理地址相互聯(lián)系,所以我們管理連續(xù)的虛擬地址就管理了物理地址,提高了效率。
進程訪問數(shù)據(jù)時,頁表會幫我們檢測訪問數(shù)據(jù)地址的合法性,如果不合法或者轉(zhuǎn)化物理地址失敗,操作系統(tǒng)就會將此進程攔截,阻止該進程,甚至終止該進程。如:一旦訪問野指針或越界,操作系統(tǒng)會終止該進程。但終止該進程不會影響到其他進程,因為是進程自己的頁表攔截了自己。所以,頁表不僅僅有地址轉(zhuǎn)化的工作,還有檢測訪問合法地址的機制。
缺頁中斷
我們申請內(nèi)存時,可能剛申請完的內(nèi)存不立即使用,如果存在這種情況,從我們申請成功到真正使用內(nèi)存的這一段時間里,操作系統(tǒng)就不好管理這部分內(nèi)存,畢竟是用戶的,也不可能銷毀,但是用戶如果一直不用,操作系統(tǒng)是無法對這部分內(nèi)存做處理的,操作系統(tǒng)的效率就會降低。
操作系統(tǒng)基于效率考慮,設計了以下機制
用戶在申請內(nèi)存后,操作系統(tǒng)首先在該進程的進程地址空間中的對應區(qū)域上面申請空間,然后返回給用戶一個虛擬地址,等到用戶真正要使用這部分內(nèi)存時,操作系統(tǒng)首先會在頁表中去查詢,若頁表中沒有該虛擬地址與物理地址的映射關系時,操作系統(tǒng)就會先中斷用戶使用該進程的操作,在物理地址上面先申請空間,在頁表中添加虛擬地址與物理地址的映射關系。再啟動該用戶使用內(nèi)存操作,操作系統(tǒng)繼續(xù)訪問頁表,通過頁表映射關系找到物理內(nèi)存,然后操作系統(tǒng)為用戶執(zhí)行對應操作即可。這個中斷操作稱為缺頁中斷。
此機制保證了內(nèi)存的使用率,提升malloc/new的速度。