4.2 地址空間(Address Spaces)
時(shí)間:2023-05-06 17:03:02 | 來源:網(wǎng)站運(yùn)營
時(shí)間:2023-05-06 17:03:02 來源:網(wǎng)站運(yùn)營
4.2 地址空間(Address Spaces):在課程最開始的回答中,很多同學(xué)都提到了,創(chuàng)造虛擬內(nèi)存的一個(gè)出發(fā)點(diǎn)是你可以通過它實(shí)現(xiàn)隔離性。如果你正確的設(shè)置了page table,并且通過代碼對它進(jìn)行正確的管理,那么原則上你可以實(shí)現(xiàn)強(qiáng)隔離。所以,我們先來回顧一下,我們期望從隔離性中得到什么樣的效果。
在我們一個(gè)常出現(xiàn)的圖中,我們有一些用戶應(yīng)用程序比如說Shell,cat以及你們自己在lab1創(chuàng)造的各種工具。在這些應(yīng)用程序下面,我們有操作系統(tǒng)位于內(nèi)核空間。
我們期望的是,每個(gè)用戶程序都被裝進(jìn)一個(gè)盒子里,這樣它們就不會(huì)彼此影響了。類似的,我們也想讓它們與內(nèi)核操作系統(tǒng)相互獨(dú)立,這樣如果某個(gè)應(yīng)用程序無意或者故意做了一些壞事,也不會(huì)影響到操作系統(tǒng)。這是我們對于隔離性的期望。
今天的課程中,我們想關(guān)注的是內(nèi)存的隔離性。如果我們不做任何工作,默認(rèn)情況下我們是沒有內(nèi)存隔離性的。你們可以回想一下,在我們上節(jié)課展示的RISC-V主板上,內(nèi)存是由一些DRAM芯片組成。在這些DRAM芯片中保存了程序的數(shù)據(jù)和代碼。例如內(nèi)存中的某一個(gè)部分是內(nèi)核,包括了文本,數(shù)據(jù),棧等等;如果運(yùn)行了Shell,內(nèi)存中的某個(gè)部分就是Shell;如果運(yùn)行了cat程序,內(nèi)存中的某個(gè)部分是cat程序。這里說的都是物理內(nèi)存,它的地址從0開始到某個(gè)大的地址結(jié)束。結(jié)束地址取決于我們的機(jī)器現(xiàn)在究竟有多少物理內(nèi)存。所有程序都必須存在于物理內(nèi)存中,否則處理器甚至都不能處理程序的指令。
這里的風(fēng)險(xiǎn)很明顯。我們簡單化一下場景,假設(shè)Shell存在于內(nèi)存地址1000-2000之間。
如果cat出現(xiàn)了程序錯(cuò)誤,將內(nèi)存地址1000,也就是Shell的起始地址加載到寄存器a0中。之后執(zhí)行
sd $7, (a0),這里等效于將7寫入內(nèi)存地址1000。
現(xiàn)在cat程序弄亂了Shell程序的內(nèi)存鏡像,所以隔離性被破壞了,這是我們不想看到的現(xiàn)象。所以,我們想要某種機(jī)制,能夠?qū)⒉煌绦蛑g的內(nèi)存隔離開來,這樣類似的事情就不會(huì)發(fā)生。一種實(shí)現(xiàn)方式是地址空間(Address Spaces)。
這里的基本概念也很簡單直觀,我們給包括內(nèi)核在內(nèi)的所有程序?qū)俚牡刂房臻g。所以,當(dāng)我們運(yùn)行cat時(shí),它的地址空間從0到某個(gè)地址結(jié)束。當(dāng)我們運(yùn)行Shell時(shí),它的地址也從0開始到某個(gè)地址結(jié)束。內(nèi)核的地址空間也從0開始到某個(gè)地址結(jié)束。
如果cat程序想要向地址1000寫入數(shù)據(jù),那么cat只會(huì)向它自己的地址1000,而不是Shell的地址1000寫入數(shù)據(jù)。所以,基本上來說,每個(gè)程序都運(yùn)行在自己的地址空間,并且這些地址空間彼此之間相互獨(dú)立。在這種不同地址空間的概念中,cat程序甚至都不具備引用屬于Shell的內(nèi)存地址的能力。這是我們想要達(dá)成的終極目標(biāo),因?yàn)檫@種方式為我們提供了強(qiáng)隔離性,cat現(xiàn)在不能引用任何不屬于自己的內(nèi)存。
所以現(xiàn)在我們的問題是如何在一個(gè)物理內(nèi)存上,創(chuàng)建不同的地址空間,因?yàn)闅w根到底,我們使用的還是一堆存放了內(nèi)存信息的DRAM芯片。
學(xué)生提問:我比較好奇物理內(nèi)存的配置,因?yàn)槲锢韮?nèi)存的數(shù)量是有限的,而虛擬地址空間存在最大虛擬內(nèi)存地址,但是會(huì)有很多個(gè)虛擬地址空間,所以我們在設(shè)計(jì)的時(shí)候需要將最大虛擬內(nèi)存地址設(shè)置的足夠小嗎?
Frans教授:并不必要,虛擬內(nèi)存可以比物理內(nèi)存更大,物理內(nèi)存也可以比虛擬內(nèi)存更大。我們馬上就會(huì)看到這里是如何實(shí)現(xiàn)的,其實(shí)就是通過page table來實(shí)現(xiàn),這里非常靈活。
同一個(gè)學(xué)生繼續(xù)問:如果有太多的進(jìn)程使用了虛擬內(nèi)存,有沒有可能物理內(nèi)存耗盡了?
Frans教授:這必然是有可能的。我們接下來會(huì)看到如果你有一些大的應(yīng)用程序,每個(gè)程序都有大的page table,并且分配了大量的內(nèi)存,在某個(gè)時(shí)間你的內(nèi)存就耗盡了。
Frans教授提問:大家們,在XV6中從哪可以看到內(nèi)存耗盡了?如果你們完成了syscall實(shí)驗(yàn),你們會(huì)知道在syscall實(shí)驗(yàn)中有一部分是打印剩余內(nèi)存的數(shù)量。
學(xué)生回答:kalloc?
Frans教授:是的,kalloc。kalloc保存了空余page的列表,如果這個(gè)列表為空或者耗盡了,那么kalloc會(huì)返回一個(gè)空指針,內(nèi)核會(huì)妥善處理并將結(jié)果返回給用戶應(yīng)用程序。并告訴用戶應(yīng)用程序,要么是對這個(gè)應(yīng)用程序沒有額外的內(nèi)存了,要么是整個(gè)機(jī)器都沒有內(nèi)存了。
內(nèi)核的一部分工作就是優(yōu)雅的處理這些情況,這里的優(yōu)雅是指向用戶應(yīng)用程序返回一個(gè)錯(cuò)誤消息,而不是直接崩潰。