抽象:地址空間

早起的操作系統其實只是一組函數(一個庫),是在內存中運行的一個運行的程序,例如下圖:

                             

其中的0-64KB,屬於操作系統,包括代碼、數據等等,64KB之後的屬於運行中的進程;

後來,隨着計算機的不斷髮展,人們開始想方設法的更有效率的使用計算機,也就是進入了多進程時代(multiprogramming),當時等等多個進程在給定時間內運行,例如當有進程在等待I/O,那麼操作系統就會將CPU交給其他進程,這樣可以讓CPU被充分的使用。後來,人們使用的程序也在不斷髮展,就開始想要更好更快的機器,於是分時系統誕生了。具體地說,就是當時的許多人認識到了批量計算的侷限性,尤其是對程序員本身,他們厭倦了長時間的低效率的程序編程-調試循環。交互(interactivity)變得重要起來,因爲在那個時代,計算機還沒有很普及,很多都是多個人,也就是一個小組、一個實驗室,甚至一家公司只有一臺計算機,於是就會出現許多個用戶同時使用一臺機器,每個人都在等待他的程序運行的情況。時分共享就是爲了解決這個問題被提出。

時分共享就是讓一個進程單獨佔用計算機所有資源,在很短的一段時間內,然後停止它,將它停止那一刻的運行信息保存在磁盤上,然後加載其他進程的運行信息,之後就對所有的進程重複這個過程,就實現了最簡單的機器共享。但是,這種方法有一個大問題:太慢了!!!特別是隨着內存的增長。:雖然保存和恢復進程狀態很快,但是把內存的全部信息都保存到磁盤上就太慢了。因此,開發者更願意將進程信息留在內存中,同時在它們之間進行切換,從而使操作系統能夠有效地實現時間共享。

將進程信息保留在內存中是有效的提升了速度,但是也帶來了安全性的問題,因爲所有進程的信息都在內存中,很有可能會有某個進程不小心的誤操作了其他進程的信息,當然惡意的故意去修改其他進程信息的情況也會出現。於是開發者們就必須開始考慮內存信息的保護問題。

於是地址空間(address space)的概念應運而生。地址空間就是內存的抽象,程序可以根據地址空間去找到對應的內存。一個進程的地址空間包含運行的程序的所有內存狀態,例如程序的代碼必須要在內存中,也就在地址空間裏,當程序運行時利用棧保存當前的函數調用信息,同時分配空間給局部變量,傳遞參數和函數返回值,再通過堆來實現程序的內存動態分配,例如C++中的new。當然還有一些其他的東西,例如靜態初始化的變量等等。

                              

上圖就是一片地址空間,它總的大小爲16KB,其中頂部是程序代碼,佔用大小爲1KB,因爲代碼是靜態的,在程序運行的過程中不會被改變,所以代碼一般都會被放置在頂層。在代碼後面,就是給運行中的程序分配的堆和棧,其中的堆放在剩餘空間的頂部,棧放置在空間底部,這樣可以允許他們同時增長,只需要他們增長的方向不同即可。當然這只是最初的堆和棧的一種分配方式,到了今天這樣的分配方式早已經被優化掉了,例如對於多個線程的時候這樣的分配就很難處理了。

到了今天,我們描述的地址空間 ,其實指的是操作系統提供給程序的抽象。因爲程序肯定不是每次都被分配在0-16KB的內存中,而是有可能加載在任意的物理地址。但是對於程序來說,它只會認爲它自己被加載在特定的地址中,一般爲0。而當程序要去操作它認爲的0地址的時候,實際上操作的物理地址可能是個任意的值,這就是內存虛擬化,也就是現代計算機系統的基礎。只有有了虛擬化的內存,纔可以良好的實現進程之間的隔離,就可以保護進程彼此之間的信息互不干擾,從而避免進程誤操作與惡意破壞的問題的發生。

有一點要注意的是,在我們平時的開發中,可以通過各種各樣的操作查看到自己使用的內存的地址,那麼這個地址是真實的嗎?當然不,通過代碼所能看到的地址都是已經經過操作系統轉換的虛擬地址,例如下面的代碼:

結果所輸出的:

this is Main address :  0x55f1fef4097a
this is a address :  0x7fffd71859a4
這兩個都是虛擬的內存地址,真正的物理控件地址需要經過操作系統與硬件翻譯才能得到。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章