為什麽 iOS 主流 App 顯示的總大小都無法對齊系統「iPhone儲存空間」內的顯示?本文分析了差異的主要原因和新版快手儲存空間頁如何做到對齊系統,透過深入研究蘋果檔案系統的機制和一系列實驗驗證,抽絲剝繭一步步確認了iOS儲存空間的顯示口徑。
全文共4072字,預計閱讀時間10分鐘。
#
背景介紹
背景
潛在影響
#
探尋差異
原因一:App自身大小
原因二:進制差異
原因三:口徑差異
原因四:統計路徑差異
#
結論
iOS儲存空間口徑
#
總結
快手對齊效果
技術視角和使用者視角的思考
一、背景介紹
我們收到使用者反饋,快手App內顯示的已用儲存空間與iOS系統設定中顯示的大小不一致。在調研了幾款主流App後發現各家顯示的大小和系統或多或少都有些差異,App的儲存空間的占用作為近些年微博熱搜的常客,這個問題引起了我們的極大的興趣和關註。
iOS 獲取App磁盤占用大小的常規方式就是透過官方NSFileManager配合NSDirectoryEnumerator遍歷所有檔來計算整體沙盒大小。但是這種方式計算的總大小始終無法和系統設定中的總大小對齊。
快手-舊版 |
微信 |
淘寶 |
|
|
iPhone儲存空間 - 總大小 |
|
|
|
|
iPhone儲存空間 - 細分 |
|
|
|
|
App內 儲存空間 - 已用空間 |
|
|
|
|
與系統的差距 |
24.9% |
8.73% |
37.93% |
12.7% |
潛在影響
App內顯示空間占用和系統不一致很容易引起使用者對我們App真實占用大小的疑問,而且多數情況下,系統顯示的總大小會明顯大於我們App內顯示數據。數據的不一致性可能會導致使用者對App的信任度下降。使用者可能會懷疑App的質素和準確性,甚至擔心私密和數據安全問題。
二、差異探尋
原因一:App自身大小
透過直接對比App內顯示已用空間和系統總大小,首先可以找到一個顯著差異:在系統中,「iPhone儲存空間」點選每個App會看到「App大小」和「文稿與數據」,除了QQ以外,其他App都沒有將自身大小計入已用空間。
對於iOS開發者來說,一個App的總大小由App大小和沙盒大小組成這一概念可能就像條件反射一樣覺得理所當然。但是對於大多數普通使用者而言,就無法理解系統「iPhone儲存空間」列表中顯示的總大小由哪些細分組成,應該用總大小還是某個細分大小對應App中顯示的大小。
所以需要從普通使用者的視角,匹配最直觀的認知方式,對齊系統「iPhone儲存空間」顯示的總大小和App內整體占用大小,將App大小也計入App整體占用大小。
原因二:進制差異
現象:為什麽1TB的硬碟實際顯示只有931GB?
當購買一塊新的流動硬碟時,會選擇不同的容量大小,512GB、1TB、2TB等等,但是當我們開啟電腦連結上時可能會發現,可用的容量比產品規格中的標註稍稍小了一點。這主要是由於儲存器材的制造商使用十進制(1000)來測量儲存容量,而一些系統顯示大小是基於二進制(1024)計算的。
假設:蘋果用的是10進制,類似硬碟規格
透過查閱蘋果官方文件[1] 我們發現,蘋果在標註器材的儲存容量時會使用10進制為標準,那麽為了配合這一口徑,系統中關於儲存容量的顯示應該也需要對齊這個口徑以減少使用者的困擾。
同時參考SI(International System of Units)、BIPM(International Bureau of Weights and Measures )等相關國際組織的定義[2] ,KB、MB和GB等單位按照標準,應使用10進制。
二進制和十進制的差異,在MB和GB級別分別會導致4.9%和7.4%的誤差[2] ,所以我們需要確認iOS系統顯示所使用的口徑是否為十進制。
驗證
可以透過對比「iPhone儲存空間」頁中的「App大小」和實際.app 大小來確認。
透過SSH登陸到越獄機後,使用Cycript註入指定行程,執行 [[NSBundle mainBundle] bundlePath]獲取對應App的.app目錄後,再使用du 命令返回.app總大小。
iPhone儲存空間 |
|
du -s 檢視當前目錄總磁盤占用空間 |
359652KiB = 359652 / 1024 = 351.22265625 MiB ≈ 351.22MiB 359652KiB = 359652 * 1024 / 1000 000 = 368.283648 MB ≈ 368.3MB |
du命令預設使用二進制進行單位轉換 [3] ,分別根據二進制和十進制轉換後,可以確認 iOS系統儲存單位為十進制 ,且保留有效小數機制為四舍五入。
無論是iOS還是macOS在使用者UI界面顯示中都采用了10進制的儲存空間單位換算,客觀上就從普通使用者感知層面避免了了類似Windows系統中硬件規格說明和系統顯示的差異問題造成的困擾。
原因三:口徑差異
現象:為什麽1B(字節)的檔磁盤大小是4KB?
Finder(訪達)看這個檔的資訊描述。
假設:檔實際大小和磁盤占用大小是兩個概念
可以看出,4KB以下小檔對結果的影響最大,而我們App沙盒中恰恰有存在大量這些小檔(縮圖、小封包、臨時緩存等),所以兩個口徑對我們整體大小的計算可能會造成非常大的差異。
1個1字節的檔 |
1萬個1字節的檔 |
1萬個10 KB的檔 |
|
檔實際大小 |
1 B |
10 000 B = 10KB |
100 000 000 B = 100 MB |
磁盤占用大小 |
4 KB |
40 000 000 B = 40 MB |
120 000 000 B = 120 MB |
差異 |
75% |
99.975% |
16.67% |
檔實際大小:是指檔自身的實際大小,1B(字節)的檔"檔實際大小"即為1B(字節)
磁盤占用大小:指檔已占用的磁盤空間(即使沒有全部被使用,剩余空間不能存放其他檔的數據,「寧缺毋濫」),1B的檔在macOS/iOS系統中"「磁盤占用大小"為4KB。查閱資料發現實際磁盤是按塊為單位進行儲存的,由於檔的大小 並不一定是塊的整數倍,因此最後一個塊可能僅被部份占用,而該塊剩余的空間將保持未使用的狀態(其他檔也不能使用)。
驗證
我們可以透過直接往App沙盒中增加 10000 個 1000B(實際檔大小)的檔到沙盒,然後檢視最終在「iPhone儲存空間」頁增量來判斷。
如果最終增量為10 MB則采用了檔實際大小計算,如果增量為40MB (10000 * 4KB)則采用了檔磁盤占用大小計算。
SSH 登入到 iPhone 後 直接在對應沙盒目錄中寫入檔
for i in {1..10000}; do dd if=/dev/zero of=file$i.txt bs=1000 count=1; done
寫入前 |
寫入後 |
|
儲存空間頁 |
|
|
「App大小」和「文稿與數據」 |
|
|
最終增量為0.04GB=40MB ,說明iPhone在計算儲存空間時使用了「磁盤占用大小 」來計算總的儲存空間占用。
App內計算磁盤占用大小
那麽我們如何在App內計算檔的「磁盤占用大小」呢?透過NSFileManager直接獲取的是檔的「檔實際大小」,而計算檔的磁盤占用大小就需要透過磁盤塊。
透過標準表頭檔stat.h的st_blocks [4] 可以獲取到塊的數量,透過 st_blocks * 512字節 可以計算出檔的磁盤占用大小。
之所以塊(磁區)大小是512字節 [5] ,這種做法源自較早的磁盤磁區大小標準。這種設計是基於早期磁盤技術的物理限制,盡管現代硬碟的物理磁區大小可能已經增加到了 4096 字節,但 512 字節的邏輯塊大小在許多檔案系統和作業系統的介面中仍然被保留。磁區是磁盤讀寫的最小物理單位節 [6] 。
當進行磁盤操作時,無論是讀取還是寫入,系統必須至少處理一個完整的磁區。這是因為磁盤的設計不允許單獨修改磁區中的一部份數據,而是必須讀取整個磁區,進行修改後再整體寫回。
實際操作中,我們發現在iOS中檔的st_blocks總是8的倍數(即使檔實際大小只有1字節),說明iOS的檔案系統(APFS)層級的最小的塊大小定義為4096字節,而APFS的官方文件中也佐證了這一觀點。
https://developer.apple.com/support/downloads/Apple-File-System-Reference.pdf
原因四:統計路徑差異 Library/Caches/
我們嘗試使用官方的 NSURLVolumeAvailableCapacityForImportantUsageKey 內容獲取iOS系統磁盤剩余空間時發現,系統並沒有把Library/Caches/ 計入已占用空間,在手機剩余容量吃緊的時候,Library/Caches/ 目錄下的內容會被系統清理。蘋果文件 File System Programming Guide [7] 也提到了儲存在不同目錄下的檔有著不同的生命周期,其中Library/Caches/ 應該儲存app執行非必須的數據。
驗證
基於這一現象,我們針對沙盒的幾大主要目錄,透過寫入已知大小的冗余檔,對系統顯示大小和App內顯示大小進行對比,確認了iOS系統納入大小統計的沙盒目錄。
App內顯示總大小 路徑範圍 |
|||||||
App大小 |
/StoreKit 目錄 |
/SystemData 目錄 |
/Library/Caches |
/Library (不包括/Library/Caches) |
/Documents |
/tmp |
|
系統口徑 |
✅ |
✅ |
✅ |
❌ |
✅ |
✅ |
✅ |
快手-舊版 |
❌ |
❌ |
❌ |
❌ |
✅ |
✅ |
✅ |
微信 |
❌ |
❌ |
❌ |
✅ |
✅ |
✅ |
✅ |
抖音 |
無總大小顯示 |
||||||
|
✅ |
❌ |
❌ |
❌ |
✅ |
✅ |
✅ |
小紅書 |
❌ |
✅ |
❌ |
✅ |
✅ |
✅ |
❌ |
iOS 17 的新問題
在本地測試我們發現 iOS17 以上系統,部份App的總大小在「iPhone儲存空間」頁的顯示邏輯和iOS16 及以下的不同。在iOS17中,部份App只含有「文稿與數據」一個細分項,沒有計入「App大小」。而根據實測發現,「文稿與數據」中計算的是整個沙盒的大小,和iOS16及以下機型「文稿與數據」中剔除了Library/Caches大小也有所區別。
只有「文稿與數據」 |
「App大小」 + 「文稿與數據」 |
|||||
|
|
|
|
|
|
|
關於iOS 17 App總大小顯示的口徑差異目前沒有定位到任何官方文件說明,且只出現在部份App上,如果大家發現相關說明/解釋 或一些不同的展示方式,歡迎聯系我們一起討論溝通
三、結論
iPhone計算App總占用空間時的計算口徑如下:
iOS 16 及以下 |
iOS 17 及以上 |
|
包含路徑 |
App大小 + App沙盒大小(剔除Library/Caches) |
App沙盒大小 |
檔大小計算方式 |
檔磁盤占用大小 |
|
儲存單位進制 |
十進制(1000) |
|
保留有效小數 |
四舍五入 |
四、總結
快手對齊後效果
在快手新版本的App中,我們不僅加入了App自身大小的統計,將儲存空間單位的進制統一切換到了10進制,還采用檔磁盤空間占用的方式來計算總大小,並對齊iOS系統計算儲存空間的路徑範圍,以便與iOS系統的顯示方式保持一致。目前,快手App內顯示的已用空間已能與iOS系統顯示基本對齊。
iPhone儲存空間-總大小 |
App記憶體儲空間-已用空間 |
差異 |
|
|
0.43% |
技術視角和使用者視角的思考
在App儲存空間的研究和最佳化中,使用者體驗始終是我們關註的核心。數據的準確性固然重要,但更加重要的是從使用者的視角出發,關註使用者在使用過程中的認知成本和直觀感受。突出整體互動的直觀性、易用性以及資訊的透明度。
處理App儲存空間的問題時,我們不僅解決了技術上的挑戰,還特別重視使用者介面的直觀性和資訊透明度。透過對齊系統大小、劃分清理模組,我們幫助使用者更加輕松地管理App儲存空間,最終增強使用者對快手的信任和滿意度。
參考資料
[1] https://support.apple.com/en-us/102119
[2] https://en.wikipedia.org/wiki/Binary_prefix#Current_practice
[3] https://man7.org/linux/man-pages/man1/du.1.html
[4] https://opensource.apple.com/source/xnu/xnu-1228.0.2/bsd/sys/stat.h.auto.html
[5] https://web.stanford.edu/ class/cs110/summer-2021/lecture-notes/lecture-02/
[6] https://en.wikipedia.org/wiki/Disk_sector
[7] https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html
來源-微信公眾號:快手大前端技術
出處:https://mp.weixin.qq.com/s/_2dzH99T1r70tYSH8z_0Ow