android開發記憶體最佳化——利用軟引用,android開發記憶體最佳化
所有Android的開發人員一定都遇到過記憶體溢出這個頭疼的問題,一旦出現這個問題,很難直接確定我們的應用是那裡出了問題,要想定位問題的原因,必須通過一些記憶體分析工具和強大的經驗積累才能快速的定位到問題具體出現在那裡。
基於移動開發具有的這個特性,本著盡量減少記憶體消耗的原則,以及我最近遇到的記憶體堆積(偶爾溢出)問題,總結一下這次解決這個問題的經驗。
問題源頭:開始App功能沒那麼多的時候,是沒有注意到這個問題的,後來功能越強越多,圖片也越來越多的時候,用ADT內建的Allocation Tracker查看了一下記憶體配置,明顯有許多無用的data object,而沒有釋放掉,開始以為是universalImageLoader的問題,以為這個開源工程對圖片的載入有問題,後來把圖片全去掉再看記憶體配置時還是有無用的data object,花了兩天時間後發現是,是自己本地的一些bitmap沒有回收,一直緩衝在記憶體中,另一個原因就是前面文章提到的,為了實現退出功能,使用了一個全域的ArrayList去儲存所有新啟動的Activity,導致Activity這種大對象無法釋放,有這兩個問題記憶體不堆積才有問題。
定位到問題的所在後,先用前面的廣播方式替換掉之前的那種方案,這樣就解決了問題的一半了,那本地圖片如何處理呢?就上網查看了一些文章,看到許多大神都說到了軟引用這個東東,於是就研究了下軟引用如何使用。發現這軟引用的確是個好東西。的確可以最佳化整個應用對記憶體的消耗。
從JDK1.2開始,java將對象分成了四種層級,以達到程式對對象生財周期的靈活控制,這四個層級由強到弱是:強引用,軟引用,弱引用,虛引用。強引用就不多說了,就是我們平時直接new出來的一個對象,不做任何的修飾,就是強引用。虛引用暫未使用過也就沒做過深入瞭解,弱引用的使用方式基本和軟引用是一樣的,所以就重點看了一下應用程式如何使用軟引用。
如果一個對象只具有軟引用,那麼如果記憶體如果夠用的話,GC就不會回收它,如果記憶體不足了,就會優先回收只有軟引用的對象記憶體,而保證不會記憶體溢出。基於軟引用的這個特性,我們可以使用軟引用來實現記憶體敏感區的快取,因此為了防止記憶體溢出的發生,在處理一些佔用記憶體較大且聲明周期較長的對象的時候,我們可以盡量使用軟引用,例如: Context及其子類對象,Drawable及其子類對象,Bitmap位元影像對象等,在建立這些類的對象的時候,盡量將其聲明為軟引用。
軟引用對象聲明: SoftReference<Class> instance;
下面兩個例子是我在項目中實際使用的代碼,大家可以看下。
//這個例子是用來處理生命週期較長的大對象 /********************************************************** * @檔案名稱:ActivityManager.java * @建立時間:2014年11月6日 上午11:38:23 * @檔案描述:Activity管理類 * @修改曆史:2014年11月6日建立初始版本 **********************************************************/public class ActivityManager{private static ActivityManager manager = null;private static HashMap<String, SoftReference<Activity>> activityMap;// 靜態語句塊,在類載入的時候一起執行static{manager = new ActivityManager();activityMap = new HashMap<String, SoftReference<Activity>>();}private ActivityManager(){}public static ActivityManager getInstance(){return manager;}public void put(Activity act){activityMap.put(act.toString(), new SoftReference<Activity>(act));}public void remove(Activity act){activityMap.remove(act.toString());}public void finishAllActivity(){Set<String> set = activityMap.keySet();Iterator<String> iter = set.iterator();while (iter.hasNext()){String actName = iter.next();Activity currentAct = activityMap.get(actName).get();if (currentAct != null){currentAct.finish();currentAct = null;}}activityMap.clear();activityMap = null;}}
//這個例子是用來處理位元影像等記憶體敏感對象樣本public class BitmapManager{private static BitmapManager bitmapManager = null;private static HashMap<String, SoftReference<Bitmap>> imageCache = null;static{bitmapManager = new BitmapManager();imageCache = new HashMap<String, SoftReference<Bitmap>>();}private BitmapManager(){}public static BitmapManager getInstance(){return bitmapManager;}public static void saveBitmapToCache(String path){Bitmap bitmap = BitmapFactory.decodeFile(path);// 添加該對象軟引用對象到Map中使其緩衝imageCache.put(path, new SoftReference<Bitmap>(bitmap));// 使用完後手動將位元影像對象置nullbitmap = null;}public static Bitmap queryBitmapByPath(String path){// 取出軟軟引用SoftReference<Bitmap> softBitmap = imageCache.get(path);// 使用時必須判斷軟引用是否回收,被回收返回空if (softBitmap == null){return null;}Bitmap bitmap = softBitmap.get();return bitmap;}} 總結:在我們開發應用程式時,最好是剛開始實現時就考慮到可能發生的問題,提前就做好這些細節性的處理,就會從根上杜絕這類問題的發生,而當問題發生了再去處理就會花費更多的精力。