[轉帖]程序員須要瞭解的硬核知識之磁盤

程序員須要瞭解的硬核知識之磁盤

 
https://www.cnblogs.com/cxuanBlog/p/11776310.html

 

此篇文章是 《程序員須要瞭解的硬核知識》系列第四篇,歷史文章請戳html

程序員須要瞭解的硬核知識以內存程序員

程序員須要瞭解的硬核知識之CPUweb

程序員須要瞭解的硬核知識之二進制小程序

咱們你們知道,計算機的五大基礎部件是 存儲器控制器運算器輸入和輸出設備,其中從存儲功能的角度來看,能夠把存儲器分爲內存和 磁盤,內存咱們上面的文章已經介紹過了,那麼此篇文章咱們來介紹一下磁盤以及內存和磁盤的關係。瀏覽器

認識磁盤

首先,磁盤和內存都具備存儲功能,它們都是存儲設備。區別在於,內存是經過電流 來實現存儲;磁盤則是經過磁記錄技術來實現存儲。內存是一種高速,造假昂貴的存儲設備;而磁盤則是速度較慢、造假低廉的存儲設備;電腦斷電後,內存中的數據會丟失,而磁盤中的數據能夠長久保留。內存是屬於內部存儲設備,硬盤是屬於 外部存儲設備。通常在咱們的計算機中,磁盤和內存是相互配合共同做業的。緩存

通常內存指的就是主存(負責存儲CPU中運行的程序和數據);早起的磁盤指的是軟磁盤(soft disk,簡稱軟盤),就是下面這個服務器

(2000年的時候我曾經我姑姑家最先的計算機中見到過這個,當時還不知道這是啥,如今知道了。)markdown

現在經常使用的磁盤是硬磁盤(hard disk,簡稱硬盤),就是下面這個網絡

程序不讀入內存就沒法運行

在瞭解磁盤前,還須要瞭解一下內存的運行機制是怎樣的,咱們的程序被保存在存儲設備中,經過使用 CPU 讀入來實現程序指令的執行。這種機制稱爲存儲程序方式,如今看來這種方式是理所固然的,但在之前程序的運行都是經過改變計算機的佈線來讀寫指令的。框架

計算機最主要的存儲部件是內存和磁盤。磁盤中存儲的程序必須加載到內存中才能運行,在磁盤中保存的程序是沒法直接運行的,這是由於負責解析和運行程序內容的 CPU 是須要經過程序計數器來指定內存地址從而讀出程序指令的。

磁盤構件

磁盤緩存

咱們上面提到,磁盤每每和內存是互利共生的關係,相互協做,彼此持有良好的合做關係。每次內存都須要從磁盤中讀取數據,必然會讀到相同的內容,因此必定會有一個角色負責存儲咱們常常須要讀到的內容。 咱們你們作軟件的時候常常會用到緩存技術,那麼硬件層面也不例外,磁盤也有緩存,磁盤的緩存叫作磁盤緩存

磁盤緩存指的是把從磁盤中讀出的數據存儲到內存的方式,這樣一來,當接下來須要讀取相同的內容時,就不會再經過實際的磁盤,而是經過磁盤緩存來讀取。某一種技術或者框架的出現勢必要解決某種問題的,那麼磁盤緩存就大大改善了磁盤訪問的速度

Windows 操做系統提供了磁盤緩存技術,不過,對於大部分用戶來講是感覺不到磁盤緩存的,而且隨着計算機的演進,對硬盤的訪問速度也在不斷演進,實際上磁盤緩存到 Windows 95/98 就已經不怎麼使用了。

把低速設備的數據保存在高速設備中,須要時能夠直接將其從高速設備中讀出,這種緩存方式在web中應用比較普遍,web 瀏覽器是經過網絡來獲取遠程 web 服務器的數據並將其顯示出來。所以,在讀取較大的圖片的時候,會耗費很多時間,這時 web 瀏覽器能夠把獲取的數據保存在磁盤中,而後根據須要顯示數據,再次讀取的時候就不用從新加載了。

虛擬內存

虛擬內存是內存和磁盤交互的第二個媒介。虛擬內存是指把磁盤的一部分做爲假想內存來使用。這與磁盤緩存是假想的磁盤(其實是內存)相對,虛擬內存是假想的內存(其實是磁盤)。

虛擬內存是計算機系統內存管理的一種技術。它使得應用程序認爲它擁有連續可用的內存(一個完整的地址空間),可是實際上,它一般被分割成多個物理碎片,還有部分存儲在外部磁盤管理器上,必要時進行數據交換。

計算機中的程序都要經過內存來運行,若是程序佔用內存很大,就會將內存空間消耗殆盡。爲了解決這個問題,WINDOWS 操做系統運用了虛擬內存技術,經過拿出一部分硬盤來看成內存使用,來保證程序耗盡內存仍然有能夠存儲的空間。虛擬內存在硬盤上的存在形式就是PAGEFILE.SYS 這個頁面文件。

經過藉助虛擬內存,在內存不足時仍然能夠運行程序。例如,在只剩 5MB 內存空間的狀況下仍然能夠運行 10MB 的程序。因爲 CPU 只能執行加載到內存中的程序,所以,虛擬內存的空間就須要和內存中的空間進行置換(swap),而後運行程序。

虛擬內存與內存的交換方式

剛纔咱們提到虛擬內存須要和內存中的部份內容作置換纔可以讓 CPU 繼續執行程序,那麼作置換的方式是怎樣的呢?又分爲哪幾種方式呢?

虛擬內存的方法有分頁式 和 分段式 兩種。Windows 採用的是分頁式。該方式是指在不考慮程序構造的狀況下,把運行的程序按照必定大小的頁進行分割,並以爲單位進行置換。在分頁式中,咱們把磁盤的內容讀到內存中稱爲 Page In,把內存的內容寫入磁盤稱爲 Page Out。Windows 計算機的頁大小爲 4KB ,也就是說,須要把應用程序按照 4KB 的頁來進行切分,以頁(page)爲單位放到磁盤中,而後進行置換。

爲了實現內存功能,Windows 在磁盤上提供了虛擬內存使用的文件(page file,頁文件)。該文件由 Windows 生成和管理,文件的大小和虛擬內存大小相同,一般大小是內存的 1 - 2 倍。

節約內存

Windows 是以圖形界面爲基礎的操做系統。它的前身是 MS-DOC,最初的版本能夠在 128kb 的內存上運行程序,可是如今想要 Windows 運行流暢的花至少要須要 512MB 的內存,但一般每每是不夠的。

也許許多人認爲可使用虛擬內存來解決內存不足的狀況,而虛擬內存確實可以在內存不足的時候提供補充,可是使用虛擬內存的 Page In 和 Page Out 一般伴隨着低速的磁盤訪問,這是一種得不償失的表現。因此虛擬內存沒法從根本上解決內存不足的狀況。

爲了從根本上解決內存不足的狀況,要麼是增長內存的容量,加內存條;要麼是優化應用程序,使其儘量變小。第一種建議每每須要衡量口袋的銀子,因此咱們只關注第二種狀況。

注意:如下的篇幅會涉及到 C 語言的介紹,是每一個程序員(不限語言)都須要知道和了解的知識。

經過 DLL 文件實現函數共有

DLL(Dynamic Link Library)文件,是一種動態連接庫 文件,顧名思義,是在程序運行時能夠動態加載 Library(函數和數據的集合)的文件。此外,多個應用能夠共有同一個 DLL 文件。而經過共有一個 DLL 文件則能夠達到節約內存的效果。

例如,假設咱們編寫了一個具備某些處理功能的函數 MyFunc()。應用 A 和 應用 B 都須要用到這個函數,而後在各自的應用程序中內置 MyFunc()(這個稱爲Static Link,靜態連接)後同時運行兩個應用,內存中就存在了同一個函數的兩個程序,這會形成資源浪費。

爲了改變這一點,使用 DLL 文件而不是應用程序的執行文件(EXE文件)。由於同一個 DLL 文件內容在運行時能夠被多個應用共有,所以內存中存在函數 MyFunc()的程序就只有一個

Windows 操做系統其實就是無數個 DLL 文件的集合體。有些應用在安裝時,DLL文件也會被追加。應用程序經過這些 DLL 文件來運行,既能夠節約內存,也能夠在不升級 EXE 文件的狀況下,經過升級 DLL 文件就能夠完成更新。

經過調用 _stdcall 來減小程序文件的大小

經過調用 _stdcall 來減少程序文件的方法,是用 C 語言編寫應用時能夠利用的高級技巧。咱們來認識一下什麼是 _stdcall。

_stdcall 是 standard call(標準調用)的縮寫。Windows 提供的 DLL 文件內的函數,基本上都是經過 _stdcall 調用方式來完成的,這主要是爲了節約內存。另外一方面,用 C 語言編寫的程序默認都不是 _stdcall 。C 語言特有的調用方式稱爲 C 調用。C 語言默認不使用 _stdcall 的緣由是由於 C 語言所對應的函數傳入參數是可變的,只有函數調用方纔能知道到底有多少個參數,在這種狀況下,棧的清理做業便沒法進行。不過,在 C 語言中,若是函數的參數和數量固定的話,指定 _stdcall 是沒有任何問題的。

C 語言和 Java 最主要的區別之一在於 C 語言須要人爲控制釋放內存空間

C 語言中,在調用函數後,須要人爲執行棧清理指令。把不須要的數據從接收和傳遞函數的參數時使用的內存上的棧區域中清理出去的操做叫作 棧清理處理

例如以下代碼

// 函數調用方 void main(){ int a; a = MyFunc(123,456); } // 被調用方 int MyFunc(int a,int b){ ... }

代碼中,從 main 主函數調用到 MyFunc() 方法,按照默認的設定,棧的清理處理會附加在 main 主函數這一方。在同一個程序中,有可能會屢次調用,致使 MyFunc() 會進行屢次清理,這就會形成內存的浪費。

彙編以後的代碼以下

push 1C8h // 將參數 456( = 1C8h) 存入棧中 push 7Bh // 將參數 123( = 7Bh) 存入棧中 call @LTD+15 (MyFunc)(00401014) // 調用 MyFunc 函數 add esp,8 // 運行棧清理

C 語言經過棧來傳遞函數的參數,使用 push 是往棧中存入數據的指令,pop 是從棧中取出數據的指令。32 位 CPU 中,1次 push 指令能夠存儲 4 個字節(32 位)的數據。上述代碼因爲進行了兩次 push 操做,因此存儲了 8 字節的數據。經過 call 指令來調用函數,調用完成後,棧中存儲的數據就再也不須要了。因而就經過 add esp,8 這個指令,使存儲着棧數據的 esp 寄存器前進 8 位(設定爲指向高 8 位字節的地址),來進行數據清理。因爲棧是在各類狀況下均可以利用的內存領域,所以使用完畢後有必要將其恢復到原始狀態。上述操做就是執行棧的清理工做。另外,在 C 語言中,函數的返回值,是經過寄存器而非棧來返回的。

棧執行清理工做,在調用方法處執行清理工做和在反覆調用方法處執行清理工做不一樣,使用 _stdcall 標準調用的方式稱爲反覆調用方法,在這種狀況下執行棧清理開銷比較小。

磁盤的物理結構

以前咱們介紹了CPU、內存的物理結構,如今咱們來介紹一下磁盤的物理結構。磁盤的物理結構指的是磁盤存儲數據的形式

磁盤是經過其物理表面劃分紅多個空間來使用的。劃分的方式有兩種:可變長方式 和 扇區方式。前者是將物理結構劃分紅長度可變的空間,後者是將磁盤結構劃分爲固定長度的空間。通常 Windows 所使用的硬盤和軟盤都是使用扇區這種方式。扇區中,把磁盤表面分紅若干個同心圓的空間就是 磁道,把磁道按照固定大小的存儲空間劃分而成的就是 扇區

扇區是對磁盤進行物理讀寫的最小單位。Windows 中使用的磁盤,通常是一個扇區 512 個字節。不過,Windows 在邏輯方面對磁盤進行讀寫的單位是扇區整數倍簇。根據磁盤容量不一樣功能,1簇能夠是 512 字節(1 簇 = 1扇區)、1KB(1簇 = 2扇區)、2KB、4KB、8KB、16KB、32KB( 1 簇 = 64 扇區)。簇和扇區的大小是相等的。

不論是硬盤仍是軟盤,不一樣的文件是不能存儲在同一簇中的,不然就會致使只有一方的文件不能刪除。因此,無論多小的文件,都會佔用 1 簇的空間。這樣一來,全部的文件都會佔用 1 簇的整數倍的空間。

咱們使用軟盤作實驗會比較簡單一些,咱們先對軟盤進行格式化,格式化後的軟盤空間以下

接下來,咱們保存一個 txt 文件,並在文件輸入一個字符,這時候文件其實只佔用了一個字節,可是咱們看一下磁盤的屬性卻佔用了 512 字節

而後咱們繼續寫入一些東西,當文件大小到達 512 個字節時,已用空間也是 512 字節,可是當咱們繼續寫入一個字符時,咱們點開屬性會發現磁盤空間會變爲 1024 個字節(= 2 簇),經過這個實驗咱們能夠證實磁盤是以簇爲單位來保存的。

文章參考:

磁盤

磁盤緩存

虛擬內存

《程序是怎樣跑起來的 第四章》

http://www.intohard.com/article-436-1.html

下面爲本身作個宣傳,歡迎關注公衆號 Java建設者,號主是Java技術棧,熱愛技術,喜歡閱讀,熱衷於分享和總結,但願能把每一篇好文章分享給成長道路上的你。關注公衆號回覆 002 領取爲你特地準備的大禮包,你必定會喜歡並收藏的。

相關文章
相關標籤/搜索