CSAPP的閱讀筆記。
在系統(tǒng)中所有的進(jìn)程之間是共享CPU和主存這些內(nèi)存資源的饶火。當(dāng)進(jìn)程數(shù)量變多時(shí)鹏控,所需要的內(nèi)存資源就會(huì)相應(yīng)的增加冬念。可能會(huì)導(dǎo)致部分程序沒(méi)有主存空間可用牧挣。此外急前,由于資源是共享的,那么就有可能導(dǎo)致某個(gè)進(jìn)程不小心寫(xiě)了另一個(gè)進(jìn)程所使用的內(nèi)存瀑构,進(jìn)而導(dǎo)致程序運(yùn)行不符合正常邏輯裆针。
為了更加有效的管理內(nèi)存并少出錯(cuò),現(xiàn)代系統(tǒng)提供了一種對(duì)主存的抽象的概念寺晌,叫做虛擬內(nèi)存(VM)世吨。
`虛擬內(nèi)存`是硬件異常、硬件地址翻譯呻征、主存耘婚、磁盤文件和內(nèi)核軟件間的完美交互,他為每個(gè)進(jìn)程提供了一個(gè)大的陆赋、一致的和私有的地址空間沐祷。
虛擬內(nèi)存提供了三個(gè)重要的能力: 緩存,內(nèi)存管理攒岛,內(nèi)存保護(hù)
1. 將主存視為一個(gè)存儲(chǔ)在磁盤上的地址空間的高速緩存赖临,在主存中只保存活動(dòng)區(qū)域,并根據(jù)需要在磁盤和主存之間來(lái)回傳送數(shù)據(jù)
2. 為每個(gè)進(jìn)程提供了一致的地址空間灾锯,簡(jiǎn)化內(nèi)存管理
3. 保護(hù)了每個(gè)進(jìn)程的地址空間不被其他進(jìn)程破壞
1.虛擬內(nèi)存作為緩存的工具
概念上兢榨,虛擬內(nèi)存被組織為一個(gè)由存放在磁盤上的N個(gè)連續(xù)字節(jié)大小的單元組成的數(shù)組。每字節(jié)都有一個(gè)唯一的虛擬地址顺饮,作為數(shù)組的索引吵聪。磁盤上的內(nèi)容被緩存在主存中。
VM系統(tǒng)將虛擬內(nèi)存分割為大小固定的塊兼雄,稱為虛擬頁(yè)(VP)吟逝,來(lái)作為磁盤和主存之間的傳輸單元。每個(gè)虛擬頁(yè)的大小為P=2^p字節(jié)君旦。類似地澎办,物理內(nèi)存也被分割為物理頁(yè)(PP)(也稱為頁(yè)幀),大小也是P字節(jié)金砍。
虛擬頁(yè)面分為三個(gè)互斥子集:
1. 未分配的:VM系統(tǒng)還未分配(或創(chuàng)建的)頁(yè)局蚀。未分配的塊沒(méi)有任何數(shù)據(jù)和它們相關(guān)聯(lián),因此也就不占用任何磁盤空間恕稠。
2. 緩存的:當(dāng)前已緩存在物理內(nèi)存中的已分配的頁(yè)琅绅。
3. 未緩存的:未緩存在物理內(nèi)存中的已分配的頁(yè)。
如上圖:有8個(gè)虛擬頁(yè)鹅巍。虛擬頁(yè)0和3未分配千扶,因此在磁盤上還不存在料祠。虛擬頁(yè)1、4和6被緩存在物理內(nèi)存中澎羞。頁(yè)2髓绽、5和7已經(jīng)被分配了,但是當(dāng)前并未緩存在主存中妆绞。
1.1頁(yè)表
虛擬內(nèi)存必須知道一個(gè)虛擬頁(yè)是否放在物理頁(yè)中顺呕,如果在物理頁(yè)中,也需知道與之關(guān)聯(lián)的物理頁(yè)的具體物理地址括饶。如果不在物理頁(yè)中株茶,需要選擇一個(gè)犧牲頁(yè)赫编,要將該虛擬頁(yè)從磁盤復(fù)制到DRAM中点弯,并將被替換的犧牲頁(yè)保存到磁盤中。
這些功能是由軟硬件聯(lián)合提供的葛家。VM系統(tǒng)要實(shí)現(xiàn)上面的功能需要操作系統(tǒng)軟件技羔、MMU(內(nèi)存管理單元)中的地址翻譯硬件和一個(gè)存放在物理內(nèi)存中叫`頁(yè)表`的數(shù)據(jù)結(jié)構(gòu)幫助僵闯。頁(yè)表就是記錄了虛擬頁(yè)和物理頁(yè)映射關(guān)系的一種數(shù)據(jù)結(jié)構(gòu)。每次地址翻譯硬件將一個(gè)虛擬地址轉(zhuǎn)換為物理地址時(shí)堕阔,都需要讀取頁(yè)表棍厂。操作系統(tǒng)負(fù)責(zé)維護(hù)頁(yè)表的內(nèi)容颗味,以及在磁盤與DRAM之間來(lái)回傳送頁(yè)超陆。
上圖展示了一個(gè)頁(yè)表的基本組織結(jié)構(gòu)。虛擬地址空間中的每個(gè)頁(yè)在頁(yè)表中一個(gè)固定偏移量處都有一個(gè)頁(yè)表?xiàng)l目(PTE)浦马。假設(shè)一個(gè)PTE由一個(gè)有效位和一個(gè)n位地址字段組成的时呀。有效位表示該虛擬頁(yè)當(dāng)前是否緩存在主存(DRAM)中。如果設(shè)置了有效位晶默,那么一個(gè)空地址表示這個(gè)虛擬頁(yè)還未被分配谨娜。否則,這個(gè)地址就指向該虛擬頁(yè)在磁盤上的起始位置磺陡。
圖中展示了8個(gè)虛擬頁(yè)和4個(gè)物理頁(yè)趴梢。四個(gè)虛擬頁(yè)(VP1、VP2币他、VP7和VP4)當(dāng)前被緩存在DRAM中坞靶。兩個(gè)頁(yè)(VP0、VP5)還未被分配蝴悉,而剩下的頁(yè)(VP3和VP6)已經(jīng)被分配了彰阴,但還未被緩存在DRAM中。
1.2頁(yè)命中
頁(yè)命中是指拍冠,該虛擬頁(yè)面是緩存的尿这。
如圖簇抵,VP2被緩存在DRAM中。當(dāng)CPU想要讀取包含在VP2中的虛擬頁(yè)的一個(gè)字時(shí)射众,地址翻譯硬件將虛擬地址作為索引并根據(jù)頁(yè)表中的PTE2來(lái)定位其物理地址碟摆,之后通過(guò)內(nèi)存總線讀取它。系統(tǒng)通過(guò)PTE2中標(biāo)志位判定VP2是已經(jīng)緩存在DRAM中叨橱。
1.3缺頁(yè)
習(xí)慣上焦履,DRAM中緩存不命中稱為缺頁(yè)。
上圖展示了在缺頁(yè)之前的頁(yè)表狀態(tài)的一個(gè)示例。CPU引用了VP3的一個(gè)字栖博,VP3并未被緩存在DRAM中屑宠。地址翻譯硬件從內(nèi)存中讀取PTE3,從有效位推斷出VP3未被緩存仇让,進(jìn)而觸發(fā)了一個(gè)缺頁(yè)異常典奉。
缺頁(yè)異常調(diào)用內(nèi)核中的缺頁(yè)異常處理程序,該程序會(huì)選擇一個(gè)犧牲頁(yè)丧叽,圖例中就是存放在PP3中的VP4卫玖。如果VP4已經(jīng)被修改了,那么內(nèi)核就會(huì)將它復(fù)制回磁盤踊淳。無(wú)論如何假瞬,內(nèi)核都會(huì)修改VP4的頁(yè)表?xiàng)l目PTE4,反映出VP4不在緩存在主存中這一事實(shí)迂尝。
然后溉躲,內(nèi)核會(huì)從磁盤復(fù)制VP3到內(nèi)存中的PP3榜田,更新PP3,隨后返回锻梳。當(dāng)異常處理程序返回時(shí)箭券,它會(huì)重新啟動(dòng)導(dǎo)致缺頁(yè)的指令,該指令會(huì)把導(dǎo)致缺頁(yè)的虛擬地址重發(fā)送到地址翻譯硬件唱蒸。但是現(xiàn)在邦鲫,VP3已經(jīng)緩存在主存中了,頁(yè)命中也能由地址翻譯硬件正常處理。
2.虛擬內(nèi)存作為內(nèi)存管理的工具
操作系統(tǒng)為每個(gè)進(jìn)程提供一個(gè)獨(dú)立的`頁(yè)表`庆捺,因而也就是獨(dú)立的虛擬地址空間古今。
如上圖所示滔以,進(jìn)程i的頁(yè)表將VP1映射到PP2捉腥,VP2映射到PP7。相似的你画,進(jìn)程j將VP1映射到PP7抵碟,VP2映射到PP10.注意,多個(gè)虛擬頁(yè)面可以映射到同一個(gè)`共享的物理頁(yè)面`上坏匪。
按需頁(yè)面調(diào)度和獨(dú)立的虛擬地址空間的結(jié)合拟逮,對(duì)系統(tǒng)內(nèi)存的使用和管理造成了深遠(yuǎn)的影響。VM簡(jiǎn)化了加載和鏈接适滓、代碼和數(shù)據(jù)的共享敦迄,以及應(yīng)用程序的內(nèi)存分配。
2.1簡(jiǎn)化鏈接
獨(dú)立地址空間允許每個(gè)進(jìn)程的內(nèi)存映像使用相同的基本格式凭迹。例如在64位x86-64平臺(tái)上罚屋,代碼段總是從虛擬地址0x400000開(kāi)始。數(shù)據(jù)段跟在代碼段后嗅绸,中間夾雜著對(duì)齊空白脾猛。棧占據(jù)用戶進(jìn)程地址空間的最高部分,并向下增長(zhǎng)鱼鸠。這樣的一致性極大地簡(jiǎn)化了鏈接器的設(shè)計(jì)和實(shí)現(xiàn)猛拴,運(yùn)行鏈接器生成完全連接的可執(zhí)行文件,這些可執(zhí)行文件是獨(dú)立于物理內(nèi)存中代碼和數(shù)據(jù)的最終位置的瞧柔。
2.2簡(jiǎn)化加載
把目標(biāo)文件(可執(zhí)行文件和共享對(duì)象文件)中的.text和.data節(jié)加載到一個(gè)新創(chuàng)建的進(jìn)程中漆弄,Linux加載器為代碼和數(shù)據(jù)段分配虛擬頁(yè),把他們標(biāo)記為無(wú)效的(即未被緩存的)造锅,將頁(yè)表?xiàng)l目指向目標(biāo)文件中適當(dāng)?shù)奈恢谩H欢兀虞d器從不從磁盤復(fù)制任何數(shù)據(jù)到內(nèi)存中哥蔚,而在每個(gè)頁(yè)被初次引用時(shí),或CPU取指令時(shí)蛛蒙,或一條正在執(zhí)行的指令引用一個(gè)內(nèi)存位置時(shí)糙箍,虛擬內(nèi)存系統(tǒng)會(huì)按需自動(dòng)調(diào)入數(shù)據(jù)頁(yè)。
2.3簡(jiǎn)化共享
一般情況下牵祟,每個(gè)進(jìn)程都有自己私有的代碼深夯、數(shù)據(jù)、堆、以及棧區(qū)域咕晋,是不和其他進(jìn)程共享的雹拄。在這種情況下,操作系統(tǒng)創(chuàng)建頁(yè)表掌呜,將相應(yīng)的虛擬頁(yè)映射到不連續(xù)的物理頁(yè)面滓玖。
獨(dú)立地址空間為操作系統(tǒng)提供了一個(gè)管理用戶進(jìn)程和操作系統(tǒng)自身之間共享的一致機(jī)制。
在部分情況下质蕉,進(jìn)程間還是需要共享代碼和數(shù)據(jù)的势篡,例如每個(gè)C程序都會(huì)調(diào)用C標(biāo)準(zhǔn)庫(kù)中的程序(printf)、都需要調(diào)用相同的內(nèi)核代碼模暗。操作系統(tǒng)通過(guò)將不同進(jìn)程中適當(dāng)?shù)奶摂M頁(yè)面映射到相同的物理頁(yè)面禁悠,從而安排多個(gè)進(jìn)程共享這部分代碼的一個(gè)副本,而不是在每個(gè)進(jìn)程中都包括單獨(dú)的內(nèi)核和C標(biāo)準(zhǔn)庫(kù)的副本兑宇。
2.4簡(jiǎn)化內(nèi)存分配
當(dāng)運(yùn)行在用戶進(jìn)程的程序要求額外的堆空間時(shí)(如調(diào)用malloc)绷蹲,操作系統(tǒng)分配k個(gè)連續(xù)的虛擬內(nèi)存頁(yè)面,并且將它們映射到物理內(nèi)存中任意位置的k個(gè)任意的物理頁(yè)面顾孽。由于頁(yè)表的存在祝钢,操作系統(tǒng)沒(méi)必要分配k個(gè)連續(xù)的物理頁(yè)面,頁(yè)面可隨機(jī)地分散在物理內(nèi)存中若厚。
3.虛擬內(nèi)存作為內(nèi)存保護(hù)的工具
操作系統(tǒng)會(huì)控制進(jìn)程對(duì)內(nèi)存系統(tǒng)的訪問(wèn)拦英,例如:
1. 不允許一個(gè)用戶進(jìn)程修改它的只讀代碼段;
2. 不允許用戶進(jìn)程讀或修改任何內(nèi)核中的代碼和數(shù)據(jù)結(jié)構(gòu)测秸;
3. 不允許用戶進(jìn)程讀或?qū)懫渌M(jìn)程的私有內(nèi)存疤估;
4. 不允許用戶進(jìn)程修改任何其他進(jìn)程共享的虛擬頁(yè)表
而提供獨(dú)立的地址空間是的區(qū)分不同進(jìn)程的私有內(nèi)存變得容易。但是霎冯,地址翻譯機(jī)制可以從一種自然的方式擴(kuò)展到提供更好的訪問(wèn)控制铃拇。CPU每次生成一個(gè)地址時(shí),地址翻譯硬件都會(huì)讀一個(gè)PTE沈撞。所以通過(guò)在PTE上添加額外的許可位來(lái)控制對(duì)一個(gè)虛擬頁(yè)面內(nèi)容的訪問(wèn)十分簡(jiǎn)單慷荔。
上圖中,在每個(gè)PTE中添加了三個(gè)許可位缠俺。SUP位表示進(jìn)程是否必須運(yùn)行在內(nèi)核模式下才能訪問(wèn)該頁(yè)显晶。運(yùn)行在內(nèi)核模式下的進(jìn)程可以訪問(wèn)任何頁(yè)面,但運(yùn)行在用戶模式中的進(jìn)程只允許訪問(wèn)那些SUP為0的頁(yè)面壹士。READ和WRITE位控制對(duì)頁(yè)面的讀和寫(xiě)訪問(wèn)磷雇。例如,如果進(jìn)程i運(yùn)行在用戶模式下躏救,那么它有讀VP0和讀寫(xiě)VP1的權(quán)限唯笙。然而,不允許訪問(wèn)VP2。
如果一條指令違反了這些許可條件崩掘,那么CPU就會(huì)觸發(fā)一個(gè)一般保護(hù)故障七嫌,將控制傳遞給一個(gè)內(nèi)核中的異常處理程序。Liunx中一般將這種異常報(bào)告為段錯(cuò)誤(segmentation fault)