android內存優化大全_中

轉載請註明本文出自大苞米的博客(http://blog.csdn.net/a396901990),謝謝支持!java


寫在最前:面試

本文的思路主要借鑑了2014年AnDevCon開發者大會的一個演講PPT,加上把網上搜集的各類內存零散知識點進行彙總、挑選、簡化後整理而成。緩存

因此我將本文定義爲一個工具類的文章,若是你在ANDROID開發中遇到關於內存問題,或者立刻要參加面試,或者就是單純的學習或複習一下內存相關知識,都歡迎閱讀。(本文最後我會盡可能列出所參考的文章)。app


OOM:工具


內存泄露能夠引起不少的問題:性能

1.程序卡頓,響應速度慢(內存佔用高時JVM虛擬機會頻繁觸發GC)學習

2.莫名消失(當你的程序所佔內存越大,它在後臺的時候就越可能被幹掉。反以內存佔用越小,在後臺存在的時間就越長)優化

3.直接崩潰(OutOfMemoryError)spa


ANDROID內存面臨的問題:操作系統

1.有限的堆內存,原始只有16M

2.內存大小消耗等根據設備,操做系統等級,屏幕尺寸的不一樣而不一樣

3.程序不能直接控制

4.支持後臺多任務處理(multitasking)

5.運行在虛擬機之上


5R:

本文主要經過以下的5R方法來對ANDROID內存進行優化:


1.Reckon(計算)

首先須要知道你的app所消耗內存的狀況,知己知彼才能百戰不殆

2.Reduce(減小)

消耗更少的資源

3.Reuse(重用)

當第一次使用完之後,儘可能給其餘的使用

5.Recycle(回收)

回收資源

4.Review(檢查)

回顧檢查你的程序,看看設計或代碼有什麼不合理的地方。



Reckon:


關於內存簡介,和Reckon(內存計算)的內容請看上一篇文章:ANDROID內存優化(大彙總——上)



Reduce :


Reduce的意思就是減小,直接減小內存的使用是最有效的優化方式。

下面來看看有哪些方法能夠減小內存使用:


Bitmap
Bitmap是內存消耗大戶,絕大多數的OOM崩潰都是在操做Bitmap時產生的,下面來看看幾個處理圖片的方法:


圖片顯示:

咱們須要根據需求去加載圖片的大小。

例如在列表中僅用於預覽時加載縮略圖(thumbnails )。

只有當用戶點擊具體條目想看詳細信息的時候,這時另啓動一個fragment/activity/對話框等等,去顯示整個圖片


圖片大小:

直接使用ImageView顯示bitmap會佔用較多資源,特別是圖片較大的時候,可能致使崩潰。 
使用BitmapFactory.Options設置inSampleSize, 這樣作能夠減小對系統資源的要求。 
屬性值inSampleSize表示縮略圖大小爲原始圖片大小的幾分之一,即若是這個值爲2,則取出的縮略圖的寬和高都是原始圖片的1/2,圖片大小就爲原始大小的1/4。 

[java]  view plain copy print ?
  1. BitmapFactory.Options bitmapFactoryOptions = new BitmapFactory.Options();  
  2. bitmapFactoryOptions.inJustDecodeBounds = true;  
  3. bitmapFactoryOptions.inSampleSize = 2;  
  4. // 這裏必定要將其設置回false,由於以前咱們將其設置成了true    
  5. // 設置inJustDecodeBounds爲true後,decodeFile並不分配空間,即,BitmapFactory解碼出來的Bitmap爲Null,但可計算出原始圖片的長度和寬度    
  6. options.inJustDecodeBounds = false;  
  7. Bitmap bmp = BitmapFactory.decodeFile(sourceBitmap, options);  


圖片像素:

Android中圖片有四種屬性,分別是:
ALPHA_8:每一個像素佔用1byte內存 
ARGB_4444:每一個像素佔用2byte內存 
ARGB_8888:每一個像素佔用4byte內存 (默認)
RGB_565:每一個像素佔用2byte內存 

Android默認的顏色模式爲ARGB_8888,這個顏色模式色彩最細膩,顯示質量最高。但一樣的,佔用的內存也最大。 因此在對圖片效果不是特別高的狀況下使用RGB_565(565沒有透明度屬性),以下:
[java]  view plain copy print ?
  1. publicstaticBitmapreadBitMap(Contextcontext, intresId) {  
  2.     BitmapFactory.Optionsopt = newBitmapFactory.Options();  
  3.     opt.inPreferredConfig = Bitmap.Config.RGB_565;  
  4.     opt.inPurgeable = true;  
  5.     opt.inInputShareable = true;  
  6.     //獲取資源圖片   
  7.     InputStreamis = context.getResources().openRawResource(resId);  
  8.     returnBitmapFactory.decodeStream(is, null, opt);  
  9. }  

圖片回收:

使用Bitmap事後,就須要及時的調用Bitmap.recycle()方法來釋放Bitmap佔用的內存空間,而不要等Android系統來進行釋放。

下面是釋放Bitmap的示例代碼片斷。

[java]  view plain copy print ?
  1. // 先判斷是否已經回收  
  2. if(bitmap != null && !bitmap.isRecycled()){  
  3.     // 回收而且置爲null  
  4.     bitmap.recycle();  
  5.     bitmap = null;  
  6. }  
  7. System.gc();  

捕獲異常:

通過上面這些優化後還會存在報OOM的風險,因此下面須要一道最後的關卡——捕獲OOM異常:

[java]  view plain copy print ?
  1. Bitmap bitmap = null;  
  2. try {  
  3.     // 實例化Bitmap  
  4.     bitmap = BitmapFactory.decodeFile(path);  
  5. catch (OutOfMemoryError e) {  
  6.     // 捕獲OutOfMemoryError,避免直接崩潰  
  7. }  
  8. if (bitmap == null) {  
  9.     // 若是實例化失敗 返回默認的Bitmap對象  
  10.     return defaultBitmapMap;  
  11. }  



修改對象引用類型:


引用類型:

引用分爲四種級別,這四種級別由高到低依次爲:強引用>軟引用>弱引用>虛引用。

強引用(strong reference)
如:Object object=new Object(),object就是一個強引用了。當內存空間不足,Java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具備強引用的對象來解決內存不足問題。

軟引用(SoftReference)
只有內存不夠時纔回收,經常使用於緩存;當內存達到一個閥值,GC就會去回收它;

弱引用(WeakReference)   

弱引用的對象擁有更短暫的生命週期。在垃圾回收器線程掃描它 所管轄的內存區域的過程當中,一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。 


虛引用(PhantomReference)   

"虛引用"顧名思義,就是形同虛設,與其餘幾種引用都不一樣,虛引用並不會決定對象的生命週期。若是一個對象僅持有虛引用,那麼它就和沒有任何引用同樣,在任什麼時候候均可能被垃圾回收。  


軟引用和弱引用的應用實例:

注意:對於SoftReference(軟引用)或者WeakReference(弱引用)的Bitmap緩存方案,如今已經不推薦使用了。自Android2.3版本(API Level 9)開始,垃圾回收器更着重於對軟/弱引用的回收,因此下面的內容能夠選擇忽略。

在Android應用的開發中,爲了防止內存溢出,在處理一些佔用內存大並且聲明週期較長的對象時候,能夠儘可能應用軟引用和弱引用技術。

下面以使用軟引用爲例來詳細說明(弱引用的使用方式與軟引用是相似的):

假設咱們的應用會用到大量的默認圖片,並且這些圖片不少地方會用到。若是每次都去讀取圖片,因爲讀取文件須要硬件操做,速度較慢,會致使性能較低。因此咱們考慮將圖片緩存起來,須要的時候直接從內存中讀取。可是,因爲圖片佔用內存空間比較大,緩存不少圖片須要不少的內存,就可能比較容易發生OutOfMemory異常。這時,咱們能夠考慮使用軟引用技術來避免這個問題發生。

首先定義一個HashMap,保存軟引用對象。

[java]  view plain copy print ?
  1. private Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>();  
再來定義一個方法,保存Bitmap的軟引用到HashMap。

[java]  view plain copy print ?
  1. public void addBitmapToCache(String path) {  
  2.        // 強引用的Bitmap對象  
  3.        Bitmap bitmap = BitmapFactory.decodeFile(path);  
  4.        // 軟引用的Bitmap對象  
  5.        SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap);  
  6.        // 添加該對象到Map中使其緩存  
  7.        imageCache.put(path, softBitmap);  
  8.    }  
獲取的時候,能夠經過SoftReference的get()方法獲得Bitmap對象。
[java]  view plain copy print ?
  1. public Bitmap getBitmapByPath(String path) {  
  2.         // 從緩存中取軟引用的Bitmap對象  
  3.         SoftReference<Bitmap> softBitmap = imageCache.get(path);  
  4.         // 判斷是否存在軟引用  
  5.         if (softBitmap == null) {  
  6.             return null;  
  7.         }  
  8.         // 取出Bitmap對象,若是因爲內存不足Bitmap被回收,將取得空  
  9.         Bitmap bitmap = softBitmap.get();  
  10.         return bitmap;  
  11.     }  
使用軟引用之後,在OutOfMemory異常發生以前,這些緩存的圖片資源的內存空間能夠被釋放掉的,從而避免內存達到上限,避免Crash發生。

須要注意的是,在垃圾回收器對這個Java對象回收前,SoftReference類所提供的get方法會返回Java對象的強引用,一旦垃圾線程回收該Java對象以後,get方法將返回null。因此在獲取軟引用對象的代碼中,必定要判斷是否爲null,以避免出現NullPointerException異常致使應用崩潰。


到底何時使用軟引用,何時使用弱引用呢?

我的認爲,若是隻是想避免OutOfMemory異常的發生,則可使用軟引用。若是對於應用的性能更在乎,想盡快回收一些佔用內存比較大的對象,則可使用弱引用。

還有就是能夠根據對象是否常用來判斷。若是該對象可能會常用的,就儘可能用軟引用。若是該對象不被使用的可能性更大些,就能夠用弱引用。

另外,和弱引用功能相似的是WeakHashMap。WeakHashMap對於一個給定的鍵,其映射的存在並不阻止垃圾回收器對該鍵的回收,回收之後,其條目從映射中有效地移除。WeakHashMap使用ReferenceQueue實現的這種機制。


其餘小tips:



相關文章
相關標籤/搜索