上一章LZ給各位展示了一下hello程序的簡單執行過程,可以看出在這一過程當中,系統在數據的傳輸上花費了大量的時間。硬件開發商為了減少這種數據傳輸的時間成本,采用一種高速緩存的技術去減少這種時間成本。
高速緩存被置放於處理器當中,與處理器中的寄存器文件直接進行數據交換,這樣大大減少了數據傳輸的時間成本,使得程序的運行速度可以得到數倍的提升。而作為一個程序猿,如果可以適當的利用高速緩存去存放一些程序運行過程中可能會經常使用的數據,可以將程序的運行速度提高數倍甚至數個數量級。
由此就可見高速緩存的重要性,下圖展示了硬件分布中,高速緩存的位置。
存儲設備的金字塔
當今的計算機系統當中,基本上全部都置入了各種各樣的存儲設備,這些存儲設備呈明顯的層次結構,它們的特點是容量越大,速度越慢。因此如果按照容量和速度將它們以圖示的方式呈現的話,則看起來就像是一個金字塔,如下所示。(非常感謝群里的猿友【夕惕若厲無咎】提供的英文電子版,這下LZ可以省去很多畫圖的功夫了)
不過這個圖是英文版的,LZ稍微解釋下,有些特別明顯的LZ就不解釋了,如果有哪位猿友實在不明白,可以到LZ的群里提問。
左邊的意思是更小更快更貴的存儲設備,包括寄存器以及L1-L3的高速緩存,以及更大更慢更便宜的存儲設備,包括主存、本地磁盤以及遠程存儲設備。通常意義下,我們將上一層的存儲設備作為當前存儲設備的高速緩存,比如L1的高速緩存是寄存器,L2的高速緩存是L1,以此類推。
操作系統是硬件的manager
操作系統是幫我們操控硬件的軟件,它就像是應用程序與硬件的中間者,在兩者之間扮演一個協調、管理的角色。它們的關系如下圖。
操作系統提供了幾個我們熟悉的概念去表示硬件設備,比如進程、虛擬存儲器、文件。它們表示的硬件設備如下圖所示。
可以看出文件是對I/O設備的抽象描述,而虛擬存儲器是對主存和I/O設備的統稱,最后,一個進程在此基礎上又加入了處理器。
進程
進程是操作系統對一個正在運行的程序的抽象。操作系統會記錄每一個進程的狀態,這些狀態就稱作進程的上下文。這些狀態主要包括了PC,寄存器以及主存的當前內容。當操作系統在進程間切換的時候,也會切換相應的上下文,從而保證進程恢復到之前的狀態。
在進程當中,又被計算機界的大神們引入了線程的概念,這些線程可以共享進程級的代碼與數據,這種共享一般比進程間的共享更加高效。
虛擬存儲器
虛擬存儲器是一種抽象描述,從物理上講,它包含了I/O設備以及主存。在邏輯上講,虛擬存儲器被描述為虛擬地址空間。下圖為進程的虛擬地址空間表示。
這里的地址自下向上依次增大,可以看出,圖中標注了起始地址,分別為0x08048000(32位)以及0x00400000(64位),然后向上分別是只讀代碼和數據、讀寫數據、運行時堆、共享庫的內存映射區間、用戶棧以及內核虛擬內存區域。
看完這個圖,LZ有一個疑問,就是這兩個32位和64位的起始地址是從何而來,於是小小的簡單探索了一下。
LZ在32位的linux系統上做了個測試,我們隨便寫一個C程序,然后使用GCC加上參數-Wl,--verbose去編譯這個文件,於是我們便可以在鏈接器腳本里看到這些內容。如下圖所示。
在里面我們可以看到0x08048000這個內存地址,__executable_start表面看來的意思是可執行的起始位置。具體這個數字的來由LZ沒有找到,我們可以先存着這個疑問,或許在書中后面的內容會解答這個疑問。(小提示:有些東西一時搞不明白,不要沉迷於此,會得不償失)
從這個地址向上則分了大致五個存儲區域。
程序代碼和數據:這些內容的起始地址就是0x08048000,首先是代碼,然后是一些全局變量。
堆:是運行時可以動態擴展的一部分內存區域,它可以由malloc和free這樣的標准庫函數操作。
共享庫:用於存放共享庫的代碼和數據。
棧:在用戶虛擬地址空間的頂部是棧,這部分區域與函數的執行有密切的關系。
內核虛擬存儲區域:內核是操作系統的一部分,就LZ粗淺的理解,內核也可以看做是一個進程,它在計算機運行期間總是在運行着,因此這部分內存區域對用戶程序是不可見的,通俗的說就是不能用。
文件
文件是I/O設備邏輯上的概念,它其實就是字節序列,也就是1和0組成的一些信息。因此所有的I/O設備,包括磁盤、鍵盤、鼠標、顯示器都可以看成是文件。
網絡
前面說了,所有的I/O設備其實都是文件這一抽象概念的具體表現,那么網絡其實也是文件的一種,因為說到底,它也可以被看做是一系列的字節序列。網絡適配器的作用就是給計算機輸入一堆被傳送過來的字節序列,這里面可能包括圖片、文字,甚至可能是代碼等等。
文章小結
本文主要介紹存儲設備的層次以及操作系統中的三個抽象概念,下一章是並發與並行的簡單介紹,也是計算機簡介的最后一章。