當前位置: 華文問答 > 遊戲

為什麽 Steam 刪除 80G 的遊戲只用了一秒?

2019-11-26遊戲

這個問題下截止到目前的回答還沒看到一個特別準確的。

既然是80G的Steam遊戲,預設作業系統是Windows,檔案系統是NTFS。Windows支持的其它檔案系統,FAT/FAT32分區最大只有8G/32G(理論上FAT32分區大小可以是2T,但Windows不允許用FAT32格式化大於32G的分區),放不下80G的遊戲,exFAT預設只能用來格式化移動儲存裝置不能用來格式化固定磁盤,所以這個問題下用FAT來解釋的回答大機率都是錯的。ReFS估計沒幾個人在用吧?

在NTFS分區裏面,一個檔,根據檔大小的不同,有3處或者5處相關的資訊:

  1. 在$MFT裏面的FILE記錄,大小固定為1K。 $MFT(Master File Table,主檔表)是NTFS最重要的檔,預設隱藏不能存取,記錄著這個分區內所有的目錄和檔資訊。一個檔在$MFT裏面的記錄主要記錄了檔名、所在資料夾的記錄號、大小、建立/上次修改/上次修改$MFT記錄/上次存取時間等內容。如果這條1K記錄剩余的空間大於檔大小,使用一個特殊的內容直接在記錄中保存檔的數據,這個內容在NTFS稱為常駐內容;如果剩余空間小於檔大小,檔數據需要使用額外的簇保存,使用另一種內容記錄這個保存這個檔數據所占用的簇,這個內容稱為非常駐內容。
  2. 在上級資料夾的索引數據中的記錄,大小不定,通常在88~600字節之間。 每個資料夾(包括根目錄)在內,會記錄本資料夾下所有子資料夾、檔的資訊,包括檔在$MFT裏面的記錄號、大小、建立/上次修改/上次修改$MFT記錄/上次存取時間等內容,這些資訊占用82字節。此外還有這個檔/子資料夾的檔名,最大255個字元,每個字元占使用unicode編碼,占兩個字節。最後會補齊8個字節。此外,為了相容DOS的8.3檔名,每個檔/子資料夾通常會有另一條檔名是8.3格式的記錄,這條記錄的大小一般不會大於96字節。
  3. 在$Secure裏面的記錄,數量和大小不定。 $Secure記錄每個檔的許可權,例如某個使用者/組對這個檔具有什麽樣的許可權。對於家用情況,沒多少使用者/組,一個檔的許可權數據通常很小不會超過4K。
  4. 在$Bitmap中對應的位。 NTFS分區中每一簇按順序對應$Bitmap檔中的1bit,0表示這一簇未被占用,1表示被占用。如果是檔在$MFT記錄中的數據內容為非常駐內容,檔所占用的每一簇在$Bitmap檔中對應的bit置1。
  5. 檔數據實際占用的簇。 一般來說稍微大一點的檔,都很可能會形成多個碎片,但這個問題是刪除檔,無需考慮碎片的情況,這個後面會提到。

根據第1項的說明,如果資料夾數據/檔大小很小的話,上面4、5兩項是沒有的。如果是簇大小為4K的NTFS分區,80G的檔在$bitmap中占用80×1024×1024÷4=20Mbit=2.5MB。如果考慮到這些簇可能散亂分布在整個分區中的不同位置,需要把整個$Bitmap檔更新一遍的話,一個1TB的分區的$Bitmap檔是32MB。

所以,每刪除一個檔/資料夾,都要更新1~4項的資訊。第5項無需更新,檔所使用的簇在$Bitmap中對應的位置0後,將來如果這些簇用來保存新的檔數據會直接覆蓋。當然,如果是使用固態硬碟的話,Windows會發送trim指令給固態的主控,主控會在空閑的時候根據磨損演算法回收對應的Page。

如果是機械硬碟的話,在沒有緩存的前提下,單是找到1~3項的記錄通常就需要十多次尋道。每一處記錄的更新必然有一次尋道,但對於固態來說只要檔數量不是太多,這個尋道(固態其實應該叫尋址更合適點)時間都可以在1秒內完成。而每一處資訊更新通常只需要寫入1簇(4K)的數據,就算是機械硬碟,這個數據傳輸時間也是基本可以忽略的,固態就更不用說了。

最後,根據前面的論述,如果一個遊戲有1024個檔的話,寫入數據量是1024×12KB=12MB,加上$Bitmap檔的2.5~32MB,總計是14.5MB~44MB。SATA固態硬碟通常4K隨機讀效能在20MB/s以上,4K寫效能100MB/s以上,在這些數據都在緩存中的前提下,還是可以在1秒內完成的。如果檔數量更少,就更加沒有壓力了。

某些回答裏面猜測的這些索引記錄是否會在Steam安裝遊戲的時候使用預分配空間是使得這些記錄集中在一起,我可以肯定不是。下圖中灰色底色的行是我電腦上的Steam裏面泰坦之旅這個遊戲的資料夾以及資料夾下若幹個檔的起始簇編號、磁區地址:

可以看到,這幾個檔/資料夾不管是$MFT記錄號還是簇編號,都並不連續。另外,這個遊戲的檔加上目錄數量不超過600。

Steam能做的,估計是把這些記錄所在的磁區緩存到記憶體中,減少讀取數據的尋道/尋址次數。畢竟前面的計算已經足以說明,就算幾個遊戲加起來如果有一千個檔,這些數據加起來也就12MB,一萬個也就120MB(不算$Bitmap),對於今天的主流配置來說這點記憶體占用完全可以忽略。而不管是刪除遊戲還是我們平時開啟遊戲來玩,就不需要從硬碟中讀取這些數據了。

最後,關於NTFS分區上如何找到一個檔的$MFT記錄號、上級資料夾的索引數據,有興趣的朋友可以看看我前幾天寫的文章: