閱讀771 返回首頁    go 魔獸


圖片的內存緩存控製

從網上找到的,自己整理了下:


    public class MemoryCache
    {
        private static final String TAG = "MemoryCache";
        /**
         * 放入緩存時是個同步操作
         * LinkedHashMap構造方法的最後一個參數true代表這個map裏的元素將按照最近使用次數由少到多排列,即LRU
         * 這樣的好處是如果要將緩存中的元素替換,則先遍曆出最近最少使用的元素來替換以提高效率
         */
        private Map<String, Bitmap> mCache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(10, 1.5f, true));
        /**
         * 緩存中圖片所占用的字節,初始0,將通過此變量嚴格控製緩存所占用的堆內存
         */
        private long mSize = 0;
        /**
         * 緩存隻能占用的最大堆內存
         */
        private long mLimit = 1000000;

        public MemoryCache() {
            setLimit(Runtime.getRuntime().maxMemory() / 10);
        }

        /**
         * 設置內存使用上限
         * @param limit
         */
        public void setLimit(long limit)  {
            mLimit = limit;
            Log.i(TAG, "MemoryCache will use up to " + (mLimit / 1024. / 1024.) + "MB");
        }

        /**
         * 獲取內存中緩存的圖片資源
         *
         * @param key
         * @return
         */
        public Bitmap get(String key) {
            try {
                if (! mCache.containsKey(key)) return null;
                return mCache.get(key);
            } catch (NullPointerException ex) {
                return null;
            }
        }

        /**
         * 將圖片資源緩存到內存
        *
         * @param key
         * @param bitmap
         */
        public void put(String key, Bitmap bitmap) {
            try {
            if (mCache.containsKey(key))
                mSize -= getSizeInBytes(mCache.get(key));
                mCache.put(key, bitmap);
                // 累計當前緩存已使用的內存大小
                mSize += getSizeInBytes(bitmap);
                checkSize();
            } catch (Throwable th) {
                th.printStackTrace();
            }
        }

        /**
         * 檢測圖片緩存的內存占用
         */
        private void checkSize()
        {
            Log.i(TAG, "cache size=" + mSize + " length=" + mCache.size());
            if (mSize > mLimit) {
                // 先遍曆最近最少使用的元素
                Iterator<Map.Entry<String, Bitmap>> iterator = mCache.entrySet().iterator();
                while (iterator.hasNext()) {
                    Map.Entry<String, Bitmap> entry = iterator.next();
                    mSize -= getSizeInBytes(entry.getValue());
                    iterator.remove();
                    if (mSize <= mLimit)
                        break;
                }
                Log.i(TAG, "Clean cache. New size " + mCache.size());
            }
        }

        /**
         * 清空內存緩存
         */
        public void clear() {
            mCache.clear();
        }

        /**
         * 圖片占用的內存
         *
         * @param bitmap
         * @return
         */
        long getSizeInBytes(Bitmap bitmap) {
            if (bitmap == null)
                return 0;
            return bitmap.getRowBytes() * bitmap.getHeight();
        }
    }

首先限製內存圖片緩衝的堆內存大小,每次有圖片往緩存裏加時判斷是否超過限製大小,超過的話就從中取出最少使用的圖片並將其移除,當然這裏如果不采用這種方式,換做軟引用也是可行的,二者目的皆是最大程度的利用已存在於內存中的圖片緩存,避免重複製造垃圾增加GC負擔,OOM溢出往往皆因內存瞬時大量增加而垃圾回收不及時造成的。隻不過二者區別在於LinkedHashMap裏的圖片緩存在沒有移除出去之前是不會被GC回收的,而SoftReference裏的圖片緩存在沒有其他引用保存時隨時都會被GC回收。所以在使用LinkedHashMap這種LRU算法緩存更有利於圖片的有效命中,當然二者配合使用的話效果更佳,即從LinkedHashMap裏移除出的緩存放到SoftReference裏,這就是內存的二級緩存,有興趣的童鞋不凡一試。

原文:https://www.eoeandroid.com/thread-254866-1-1.html

最後更新:2017-04-03 12:55:04

  上一篇:go SQL Server 2008 R2用戶&#39;sa&#39;登錄失敗(錯誤18456)
  下一篇:go 設計模式之工廠方法模式