Android記憶體優化之記憶體快取

codeceo發表於2015-08-22

什麼是快取?

快取技術原理就是把使用者訪問的所有物件看作一個全集,經過演算法標記哪些是使用者經常訪問的物件,把這些物件放到一個集合裡,這個集合是全集一個子集,下一次使用者再訪問的時候會先從這個子集集合中查詢使用者要訪問的物件如果找到就直接返回這個物件,如果沒有找到則再去全集中查詢。當然了我這裡說的只是原理性的東西,快取是有很多演算法的,並且有的不止一級快取,這裡就不過多講了。

為什麼要用到快取?

有快取的話可以不必每次從源地址讀取檔案,既節省了時間也節省了流量。尤其是手機裝置,頻繁的訪問網路資源會消耗很多使用者的流量和電量,這是使用者不能忍受的,所以無論從哪個方面考慮應用程式都必須加上快取。

Android中的圖片快取有哪些?各有什麼特點?

Android裝置的圖片快取分兩種,一種是記憶體快取,圖片快取在裝置的記憶體中,一種是外部快取,圖片快取在磁碟上,磁碟可以是內部的儲存空間也可以是外部的sd卡。這兩種快取各有各的優點,記憶體快取優點是快,缺點是因為也是讀取到記憶體中所以也會消耗記憶體,所以不能太大,用的時候要考慮分配的空間,還有一個缺點是應用重啟後就會消失。外部快取的優點是可以長久儲存大量的資料(相比較記憶體快取而言),缺點就是慢。

記憶體快取:

在Android中官網推薦使用LruCache作為記憶體快取,LruCache實際上就是一個LinkedHashMap( 補充知識:LinkedHashMap是一個雙向迴圈列表,不支援執行緒安全,LruCache對它進行了封裝新增了執行緒安全操作),裡面儲存了一定數量的物件強引用,每次新增的新物件都是在連結串列的頭,當分配的空間用完的時候會把末尾的物件移除,移除的物件就可以被gc回收了。這裡需要注意一下LruCache的容量,這個容量既不能太大,會造成OOM,又不能太小,起不到快取的作用。google官網給出一下意見作為參考:

  • 分配LruCache大小的時候考慮你的應用剩餘記憶體有多大;
  • 一次螢幕顯示多少張圖片,有多少張圖片是快取起來準備顯示的;
  • 考慮你的手機解析度和尺寸, 快取相同的圖片個數,dpi越大的手機需要的記憶體就會越大;
  • 圖片解析度和畫素質量也決定了佔用記憶體的大小;
  • 圖片訪問的頻繁程度是多少,是不是有一些圖片是經常訪問的?如果存在你可以考慮用多個·LruCache來做快取,按照訪問的頻率度分配到不同的LruCache中;
  • 如何平衡一下圖片質量和數量,有些時候可以考慮快取低解析度的圖片,用到的時候再在後臺請求更高質量的圖片;
  • 總之你分配的LruCache大小既不能太大,又不能太小,具體到應用中還要你綜合考慮。

下面的程式碼是使用LruCache的例子:

private LruCache<String, Bitmap> mMemoryCache;//宣告快取空間

final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);//獲取應用在系統中的最大記憶體分配

//分配1/8的應用記憶體作為快取空間

final int cacheSize = maxMemory / 8;

mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {

@Override

protected int sizeOf(String key, Bitmap bitmap) {

//重寫sizeOf方法,返回圖片的佔用位元組數而不是圖片的個數,每次新增圖片是會被呼叫

return bitmap.getByteCount() / 1024;

         }

};

注意:有同學可能會問下面的程式碼:

  intcacheSize=4*1024*1024;// 4MiB

  LruCachebitmapCache=newLruCache(cacheSize){

  protectedintsizeOf(Stringkey,Bitmapvalue){

  returnvalue.getByteCount();

      }

  }

這兩個sizeOf的計算是不一樣的,這裡說明一下,這個方法重寫的目的是返回圖片佔用的快取空間而不是圖片的數目,並且這個數值的單位要和cacheSize一樣。

總結:

綜合上面的講解,在使用記憶體快取LruCache時你需要知道如下知識:

LruCache封裝了LinkedHashMap,提供了LRU(Least Recently Used 最近最少使用演算法)快取的功能;

LruCache通過trimToSize方法自動刪除最近最少訪問的鍵值對;

LruCache不允許空鍵值, LinkedHashMap允許;

LruCache執行緒安全, LinkedHashMap執行緒不安全;

繼承LruCache時,必須要複寫sizeOf方法,用於計算每個條目的大小。在put和get的時候會呼叫safeSizeOf(K key, V value),safeSizeOf(K key, V value)會呼叫 sizeOf (K key, V value),這個方法預設返回1。

另外推薦一款第三方的內測工具對APP進行全方面的檢測:http://www.ineice.com/

相關文章