中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Bitmap引起的OOM問題怎么解決

發布時間:2023-04-28 16:04:54 來源:億速云 閱讀:73 作者:iii 欄目:開發技術

這篇文章主要講解了“Bitmap引起的OOM問題怎么解決”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Bitmap引起的OOM問題怎么解決”吧!

1.什么是OOM?為什么會引起OOM?

答:Out Of Memory(內存溢出),我們都知道Android系統會為每個APP分配一個獨立的工作空間,或者說分配一個單獨的Dalvik虛擬機,這樣每個APP都可以獨立運行而不相互影響!而Android對于每個Dalvik虛擬機都會有一個最大內存限制,如果當前占用的內存加上我們申請的內存資源超過了這個限制,系統就會拋出OOM錯誤!另外,這里別和RAM混淆了,即時當前RAM中剩余的內存有1G多,但是OOM還是會發生!別把RAM(物理內存)和OOM扯到一起!另外RAM不足的話,就是殺應用了,而不是僅僅是OOM了!而這個Dalvik中的最大內存標準,不同的機型是不一樣的,可以調用:

ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
Log.e("HEHE","最大內存:" + activityManager.getMemoryClass());

獲得正常的最大內存標準,又或者直接在命令行鍵入:

adb shell getprop | grep dalvik.vm.heapgrowthlimit

你也可以打開系統源碼/system/build.prop文件,看下文件中這一部分的信息得出:

dalvik.vm.heapstartsize=8m
dalvik.vm.heapgrowthlimit=192m
dalvik.vm.heapsize=512m
dalvik.vm.heaptargetutilization=0.75
dalvik.vm.heapminfree=2m
dalvik.vm.heapmaxfree=8m

你也可以試試自己手頭的機子~

好啦,不扯了,關于OOM問題的產生,就扯到這里,再扯就到內存管理那一塊了,可是個大塊頭,現在還啃不動...下面我們來看下避免Bitmap OOM的一些技巧吧!

2.避免Bitmap引起的OOM技巧小結

1)采用低內存占用量的編碼方式

上一節說了BitmapFactory.Options這個類,我們可以設置下其中的inPreferredConfig屬性,默認是Bitmap.Config.ARGB_8888,我們可以修改成Bitmap.Config.ARGB_4444Bitmap.Config ARGB_4444:每個像素占四位,即A=4,R=4,G=4,B=4,那么一個像素點占4+4+4+4=16位Bitmap.Config ARGB_8888:每個像素占八位,即A=8,R=8,G=8,B=8,那么一個像素點占8+8+8+8=32位默認使用ARGB_8888,即一個像素占4個字節!

2)圖片壓縮

同樣是BitmapFactory.Options,我們通過inSampleSize設置縮放倍數,比如寫2,即長寬變為原來的1/2,圖片就是原來的1/4,如果不進行縮放的話設置為1即可!但是不能一味的壓縮,畢竟這個值太小的話,圖片會很模糊,而且要避免圖片的拉伸變形,所以需要我們在程序中動態的計算,這個inSampleSize的合適值,而Options中又有這樣一個方法:inJustDecodeBounds,將該參數設置為true后,decodeFiel并不會分配內存空間,但是可以計算出原始圖片的長寬,調用options.outWidth/outHeight獲取出圖片的寬高,然后通過一定的算法,即可得到適合的inSampleSize,這里感謝街神提供的代碼——摘自鴻洋blog!

public static int caculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    int width = options.outWidth;
    int height = options.outHeight;
    int inSampleSize = 1;
    if (width > reqWidth || height > reqHeight) {
        int widthRadio = Math.round(width * 1.0f / reqWidth);
        int heightRadio = Math.round(height * 1.0f / reqHeight);
        inSampleSize = Math.max(widthRadio, heightRadio);
    }
    return inSampleSize;
}

然后使用下上述的方法即可:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // 設置了此屬性一定要記得將值設置為false
Bitmap bitmap = null;
bitmap = BitmapFactory.decodeFile(url, options);
options.inSampleSize = computeSampleSize(options,128,128);
options.inPreferredConfig = Bitmap.Config.ARGB_4444;
/* 下面兩個字段需要組合使用 */  
options.inPurgeable = true;
options.inInputShareable = true;
options.inJustDecodeBounds = false;
try {
    bitmap = BitmapFactory.decodeFile(url, options);
} catch (OutOfMemoryError e) {
        Log.e(TAG, "OutOfMemoryError");
}

3.及時回收圖像

如果引用了大量的Bitmap對象,而應用又不需要同時顯示所有圖片。可以將暫時不用到的Bitmap對象及時回收掉。對于一些明確知道圖片使用情況的場景可以主動recycle回收,比如引導頁的圖片,使用完就recycle,幀動畫,加載一張,畫一張,釋放一張!使用時加載,不顯示時直接置null或recycle!比如:imageView.setImageResource(0); 不過某些情況下會出現特定圖片反復加載,釋放,再加載等,低效率的事情...

4.其他方法

1.簡單通過SoftReference引用方式管理圖片資源

建個SoftReference的hashmap使用圖片時先查詢這個hashmap是否有softreference, softreference里的圖片是否為空,如果為空就加載圖片到softreference并加入hashmap。無需再代碼里顯式的處理圖片的回收與釋放,gc會自動處理資源的釋放。這種方式處理起來簡單實用,能一定程度上避免前一種方法反復加載釋放的低效率。但還不夠優化。

示例代碼:

private Map<String, SoftReference<Bitmap>> imageMap 
                                           = new HashMap<String, SoftReference<Bitmap>>();

public Bitmap loadBitmap(final String imageUrl,final ImageCallBack imageCallBack) {
    SoftReference<Bitmap> reference = imageMap.get(imageUrl);
    if(reference != null) {
        if(reference.get() != null) {
            return reference.get();
        }
    }
    final Handler handler = new Handler() {
        public void handleMessage(final android.os.Message msg) {
            //加入到緩存中
            Bitmap bitmap = (Bitmap)msg.obj;
            imageMap.put(imageUrl, new SoftReference<Bitmap>(bitmap));
            if(imageCallBack != null) {
                imageCallBack.getBitmap(bitmap);
            }
        }
    };
    new Thread(){
        public void run() {
            Message message = handler.obtainMessage();
            message.obj = downloadBitmap(imageUrl);
            handler.sendMessage(message);
        }
    }.start();
    return null ;
}

// 從網上下載圖片
private Bitmap downloadBitmap (String imageUrl) {
    Bitmap bitmap = null;
    try {
        bitmap = BitmapFactory.decodeStream(new URL(imageUrl).openStream());
        return bitmap ;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    } 
}
public interface ImageCallBack{
    void getBitmap(Bitmap bitmap);
}

2.LruCache + sd的緩存方式

Android 3.1版本起,官方還提供了LruCache來進行cache處理,當存儲Image的大小大于LruCache 設定的值,那么近期使用次數最少的圖片就會被回收掉,系統會自動釋放內存!

使用示例

步驟:

1)要先設置緩存圖片的內存大小,我這里設置為手機內存的1/8,手機內存的獲取方式:int MAXMEMONRY = (int) (Runtime.getRuntime() .maxMemory() / 1024);

2)LruCache里面的鍵值對分別是URL和對應的圖片

3)重寫了一個叫做sizeOf的方法,返回的是圖片數量。

private LruCache<String, Bitmap> mMemoryCache;
private LruCacheUtils() {
    if (mMemoryCache == null)
        mMemoryCache = new LruCache<String, Bitmap>(
                MAXMEMONRY / 8) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                // 重寫此方法來衡量每張圖片的大小,默認返回圖片數量。
                return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
            }

            @Override
            protected void entryRemoved(boolean evicted, String key,
                    Bitmap oldValue, Bitmap newValue) {
                Log.v("tag", "hard cache is full , push to soft cache");
               
            }
        };
}

4)下面的方法分別是清空緩存、添加圖片到緩存、從緩存中取得圖片、從緩存中移除。

移除和清除緩存是必須要做的事,因為圖片緩存處理不當就會報內存溢出,所以一定要引起注意。

public void clearCache() {
    if (mMemoryCache != null) {
        if (mMemoryCache.size() > 0) {
            Log.d("CacheUtils",
                    "mMemoryCache.size() " + mMemoryCache.size());
            mMemoryCache.evictAll();
            Log.d("CacheUtils", "mMemoryCache.size()" + mMemoryCache.size());
        }
        mMemoryCache = null;
    }
}

public synchronized void addBitmapToMemoryCache(String key, Bitmap bitmap) {
    if (mMemoryCache.get(key) == null) {
        if (key != null && bitmap != null)
            mMemoryCache.put(key, bitmap);
    } else
        Log.w(TAG, "the res is aready exits");
}

public synchronized Bitmap getBitmapFromMemCache(String key) {
    Bitmap bm = mMemoryCache.get(key);
    if (key != null) {
        return bm;
    }
    return null;
}

/**
 * 移除緩存
 * 
 * @param key
 */
public synchronized void removeImageCache(String key) {
    if (key != null) {
        if (mMemoryCache != null) {
            Bitmap bm = mMemoryCache.remove(key);
            if (bm != null)
                bm.recycle();
        }
    }
}

感謝各位的閱讀,以上就是“Bitmap引起的OOM問題怎么解決”的內容了,經過本文的學習后,相信大家對Bitmap引起的OOM問題怎么解決這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

盘锦市| 兴和县| 武功县| 荥阳市| 鄯善县| 江达县| 德安县| 昭通市| 泰安市| 和静县| 青冈县| 德令哈市| 扶风县| 辽阳市| 休宁县| 黄石市| 洛扎县| 天柱县| 昂仁县| 游戏| 凤山市| 克什克腾旗| 沐川县| 惠东县| 海伦市| 神池县| 乌什县| 旺苍县| 禹州市| 新乐市| 汉源县| 乐平市| 同仁县| 荆州市| 镇坪县| 太康县| 尼玛县| 鲁山县| 岗巴县| 镶黄旗| 泗洪县|