java中垃圾回收器(GC)的核心思想:對虛擬機可用的內存空間,即堆空間中的對象進行識別,若是對象再也不被引用,則GC回收其所佔用的內存空間用於再分配。 java
Bitmap:圖片資源通常很是消耗內存。Android系統中分給虛擬機中的圖片堆棧大小隻有8MB,若是超出了,則會OOM。 緩存
Java有本身GC,爲何還要顯示的調用recycle()呢? 服務器
答:Bitmap類的構造方法是私有的,因此不能new一個新對象,只能經過BitmapFactory的各類靜態方法來實例化一個Bitmap。由BitmapFactory的源碼可知,生成Bitmap是經過JNI來實現的。因此加載Bitmap到內存空間包含兩部份內存區域:Java部分和C部分。Java部分不用的時候會有GC來回收,可是C部分只能經過調用底層的功能來釋放。因此這裏須要經過recycle()代碼裏調用JNI來釋放C部分的內存。 網絡
雖然系統可能爲你釋放Bitmap的內存空間,可是,最好由本身及時釋放。 spa
//先判斷是否已經回收 if(bitmap != null && !bitmap.isRecycled()) { //回收而且置爲null bitmap.recycle(); bitmap = null; }
爲了不在分配Bitmap內存的時候出現OOM異常而致使程序Crash掉,一般,需在Bitmap實例化部分進行OOM異常的捕獲,若是捕捉到OOM異常,則返回一個默認的Bitmap圖。 code
Bitmap bimap = null; try { //實例化Bitmap bitmap = BitmapFactory.decodeFile(path); }catch(OutOfMemoryError e) { //...... } if(bitmap == null) { return defaultBitmapMap; }
注意:不少開發者會習慣性的在上面代碼中捕獲Exception。可是可能讓他們失望了,由於OutOfMemoryError從名字就能夠看出來是一種Error,而不是Exception。 對象
有時候,可能須要在一個應用中屢次用到同一張圖片,好比用戶圖像列表等。而用戶沒有設置頭像的話,則會顯示一個默認的頭像,而這個頭像是存放在資源文件中的。 圖片
諸如此類的狀況,咱們就能夠對同一Bitmap進行緩存。若是不緩存,則每次實例化獲得的都是不一樣Bitmap對象,這樣會形成內存的浪費。 內存
緩存通常有兩個級別: 資源
硬盤緩存:好比開發網絡應用中,能夠將一些從網絡上獲取的數據保存到SD卡中,下次直接從SD卡獲取;
內存緩存:好比應用程序中常常用到同一對象,則能夠把它放到內存中緩存起來,須要的時候從內存中直接獲取。
在上面已經提到過Android系統給圖片的堆棧空間就8M,因此若是圖片像素過大,超出此限制,則一定會形成OOM。這個時候,一般須要將圖片縮小,以減小圖片載入過程當中內存的使用。
壓縮圖片這一系列操做要用到BitmapFactory.Options。
//得到Options對象 BitmapFactory.Options opts = new BitmapFactory.Options(); //設置inJustDecodeBounds爲true,保證生成的Bitmap對象爲null opts.inJustDecodeBounds = true; //使用decodeFile方法爲了得到圖片的寬和高 BitmapFactory.decodeFile(path,opts); //打印圖片的寬和高 Log.d("example",opts.outWidth + "," + opts.outHeight);
上面代碼得到圖片寬高以後,判斷圖片是否須要壓縮,若是須要壓縮,則設置Options的inSampleSize屬性,好比設置爲2,即將圖片的寬高分別縮小爲原來的1/2,則整個圖片縮小1/4。不須要壓縮,固然將inSampleSize設置爲1。須要注意的是。在下次使用BitmapFactory的decodeFile()等方法實例化Bitmap對象前,別忘了將inJustDecodeBound設置爲false,不然獲得的Bitmap對象爲null。
對於本地或本身服務器上的圖片的大小本身可能還內心有數,可是特別對於來自外界,好比網絡上的圖片,獲取前判斷是否須要壓縮就顯得尤其重要了。