iOS圖片載入速度極限最佳化—FastImageCache解析

來源:互聯網
上載者:User

標籤:

本文轉載至 http://blog.cnbang.net/tech/2578/

FastImageCache是Path團隊開發的一個開源庫,用於增益圖片的載入和渲染速度,讓基於圖片的列表滑動起來更順暢,來看看它是怎麼做的。

最佳化點

iOS從磁碟載入一張圖片,使用UIImageVIew顯示在螢幕上,需要經過以下步驟:

  1. 從磁碟拷貝資料到核心緩衝區
  2. 從核心緩衝區複製資料到使用者空間
  3. 產生UIImageView,把映像資料賦值給UIImageView
  4. 如果映像資料為未解碼的PNG/JPG,解碼為位元影像資料
  5. CATransaction捕獲到UIImageView layer樹的變化
  6. 主線程Runloop提交CATransaction,開始進行映像渲染
    • 6.1 如果資料沒有位元組對齊,Core Animation會再拷貝一份資料,進行位元組對齊。
    • 6.2 GPU處理位元影像資料,進行渲染。

FastImageCache分別最佳化了2,4,6.1三個步驟:

  1. 使用mmap記憶體映射,省去了上述第2步資料從核心空間拷貝到使用者空間的操作。
  2. 緩衝解碼後的位元影像資料到磁碟,下次從磁碟讀取時省去第4步解碼的操作。
  3. 產生位元組對齊的資料,防止上述第6.1步CoreAnimation在渲染時再拷貝一份資料。

接下來具體介紹這三個最佳化點以及它的實現。

記憶體映射

平常我們讀取磁碟上的一個檔案,上層API調用到最後會使用系統方法read()讀取資料,核心把磁碟資料讀入核心緩衝區,使用者再從核心緩衝區讀取資料複製到使用者記憶體空間,這裡有一次記憶體拷貝的時間消耗,並且讀取後整個檔案資料就已經存在於使用者記憶體中,佔用了進程的記憶體空間。

FastImageCache採用了另一種讀寫檔案的方法,就是用mmap把檔案對應到使用者空間裡的虛擬記憶體,檔案中的位置在虛擬記憶體中有了對應的地址,可以像操作記憶體一樣操作這個檔案,相當於已經把整個檔案放入記憶體,但在真正使用到這些資料前卻不會消耗實體記憶體,也不會有讀寫磁碟的操作,只有真正使用這些資料時,也就是映像準備渲染在螢幕上時,虛擬記憶體管理系統VMS才根據缺頁載入的機制從磁碟載入對應的資料區塊到實體記憶體,再進行渲染。這樣的檔案讀寫檔案方式少了資料從核心緩衝到使用者空間的拷貝,效率很高。

解碼映像

一般我們使用的映像是JPG/PNG,這些映像資料不是位元影像,而是是經過編碼壓縮後的資料,使用它渲染到螢幕之前需要進行解碼轉成位元影像資料,這個解碼操作是比較耗時的,並且沒有GPU硬解碼,只能通過CPU,iOS預設會在主線程對映像進行解碼。很多庫都解決了映像解碼的問題,不過由於解碼後的映像太大,一般不會緩衝到磁碟,SDWebImage的做法是把解碼操作從主線程移到子線程,讓耗時的解碼操作不佔用主線程的時間。

FastImageCache也是在子線程解碼映像,不同的是它會緩衝解碼後的映像到磁碟。因為解碼後的映像體積很大,FastImageCache對這些映像資料做了系列緩衝管理,詳見下文實現部分。另外緩衝的映像體積大也是使用記憶體映射讀取檔案的原因,小檔案使用記憶體映射無優勢,記憶體拷貝的量少,拷貝後佔用使用者記憶體也不高,檔案越大記憶體映射優勢越大。

位元組對齊

Core Animation在映像資料非位元組對齊的情況下渲染前會先拷貝一份映像資料,官方文檔沒有對這次拷貝行為作說明,模擬器和Instrument裡有高亮顯示“copied images”的功能,但似乎它有bug,即使某張圖片沒有被高亮顯示出渲染時被copy,從呼叫堆疊上也還是能看到調用了CA::Render::copy_image方法:

那什麼是位元組對齊呢,按我的理解,為了效能,底層渲染映像時不是一個像素一個像素渲染,而是一塊一塊渲染,資料是一塊塊地取,就可能遇到這一塊連續的記憶體資料裡結尾的資料不是映像的內容,是記憶體裡其他的資料,可能越界讀取導致一些奇怪的東西混入,所以在渲染之前CoreAnimation要把資料拷貝一份進行處理,確保每一塊都是映像資料,對於不足一塊的資料置空。大致圖示:(pixel是映像像素資料,data是記憶體裡其他資料)

塊的大小應該是跟CPU cache line有關,ARMv7是32byte,A9是64byte,在A9下CoreAnimation應該是按64byte作為一塊資料去讀取和渲染,讓映像資料對齊64byte就可以避免CoreAnimation再拷貝一份資料進行修補。FastImageCache做的位元組對齊就是這個事情。

實現

FastImageCache把同個類型和尺寸的映像都放在一個檔案裡,根據檔案位移取單張圖片,類似web的css雪碧圖,這裡稱為ImageTable。這樣做主要是為了方便統一管理圖片緩衝,控制緩衝的大小,整個FastImageCache就是在管理一個個ImageTable的資料。整體實現的資料結構

一些補充和說明:

ImageTable
  1. 一個ImageFormat對應一個ImageTable,ImageFormat指定了ImageTable裡映像渲染格式/大小等資訊,ImageTable裡的映像資料都由ImageFormat規定了統一的尺寸,每張映像大小都是一樣的。
  2. 一個ImageTable一個實體檔案,並有另一個檔案儲存這個ImageTable的meta資訊。
  3. 映像使用entityUUID作為唯一標示符,由使用者定義,通常是映像url的hash值。ImageTable Meta的indexMap記錄了entityUUID->entryIndex的映射,通過indexMap就可以用映像的entityUUID找到快取資料在ImageTable對應的位置。
ImageTableEntry
  1. ImageTable的實體資料是ImageTableEntry,每個entry有兩部分資料,一部分是對齊後的映像資料,另一部分是meta資訊,meta儲存這張映像的UUID和原圖UUID,用於校正映像資料的正確性。
  2. Entry資料是按記憶體分頁大小對齊的,資料大小是記憶體分頁大小的整數倍,這樣可以保證虛擬記憶體缺頁載入時使用最少的記憶體頁載入一張映像。
  3. 映像資料做了位元組對齊處理,CoreAnimation使用時無需再處理拷貝。具體做法是CGBitmapContextCreate建立位元影像畫布時bytesPerRow參數傳64倍數。
Chunk
  • ImageTable和實體資料Entry間多了層Chunk,Chunk是邏輯上的資料劃分,N個Entry作為一個Chunk,記憶體映射mmap操作是以chunk為單位的,每一個chunk執行一次mmap把這個chunk的內容映射到虛擬記憶體。為什麼要多一層chunk呢,按我的理解,這樣做是為了靈活控制mmap的大小和調用次數,若對整個ImageTable執行mmap,載入虛擬記憶體的檔案過大,若對每個Entry做mmap,調用次數會太多。
緩衝管理
  • 使用者可以定義整個ImageTable裡最大緩衝的映像數量,在有新映像需要緩衝時,如果緩衝沒有超過限制,會以chunk為單位擴充檔案大小,順序寫下去。如果已超過最大緩衝限制,會把最少使用的緩衝替換掉,實現方法是每次使用映像都會把UUID插入到MRUEntries數組的開頭,MRUEntries按最近使用順序排列了映像UUID,數組裡最後一個映像就是最少使用的。被替換掉的圖片下次需要再使用時,再走一次取原圖—解壓—儲存的流程。
使用

FastImageCache適合用於tableView裡緩衝每個cell上同樣規格的映像,優點是能極大加快第一次從磁碟載入這些映像的速度。但它有兩個明顯的缺點:一是占空間大。因為緩衝瞭解碼後的位元影像到磁碟,位元影像是很大的,寬高100*100的映像在2x的高清屏裝置下就需要200*200*4byte/pixel=156KB,這也是為什麼FastImageCache要大費周章限制緩衝大小。二是介面不友好,需預定義好緩衝的映像尺寸。FastImageCache無法像SDWebImage那樣無縫接入UIImageView,使用它需要配置ImageTable,定義好尺寸,手動提供的原圖,每種實體映像要定義一個FICEntity模型,使邏輯變複雜。

FastImageCache已經屬於極限最佳化,做映像載入/渲染最佳化時應該優先考慮一些低代價高回報的最佳化點,例如CALayer代替UIImageVIew,減少GPU計算(去透明/像素對齊),映像子線程解碼,避免Offscreen-Render等。在其他最佳化都做到位,映像的渲染還是有效能問題的前提下才考慮使用FastImageCache進一步提升首次載入的效能,不過位元組對齊的最佳化倒是可以脫離FastImageCache直接運用在項目上,只需要在解碼映像時bitmap畫布的bytesPerRow設為64的倍數即可。

iOS圖片載入速度極限最佳化—FastImageCache解析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.