Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Studido下的應用性能優化總結-內存優化

Android Studido下的應用性能優化總結-內存優化

編輯:關於Android編程

  上一篇文章總結的布局優化的問題,如果對布局優化不是很熟悉的,可以看一下Android Studido下的應用性能優化總結–布局優化 , 這周一直籌劃總結一下內存優化的問題,因為現在對於應用優化的文章很多,但是還是想完善一下才想分享這篇文章的,我會從項目中遇到的一個問題,通過解決問題的過程來分享知識,希望大家有所收獲。

  “A small leak will sink a great ship.” - Benjamin Franklin

  小樓不修補,大船也會翻。——本傑明 富蘭克林


出現的問題(What)

場景(Scene): Y君某年某月某日碰到一個奇怪的問題:A頁面跳轉到B頁面,然後跳轉到其他頁面沒有問題,但是在A跳轉B,然後B跳轉到A頁面,就開始發生卡頓,程序也不崩潰!!OMG,這是什麼問題,Y君當時確實有點懵逼了,這是腫麼一個情況,但是Y君畢竟也是上過刀山下過火海,在bug堆裡走出來的人(突然想起了那句話,我要成為海賊王的男人…),扯遠了,還是回到問題上來.

分析問題(Why)

由於出現卡頓現象,大部分都出自內存的問題上,所以我們開始分析自己應用的內存使用情況,但是問題來了,用什麼工具查看應用的內存使用情況?
因為以前Ecliplse的內存查看略顯繁瑣,而且Goole推出的新的開發工具Android Studio,有很多我們方便我們安卓開發程序猿調試和分析問題,在這裡我就介紹一下Android Studio中的內存分析工具Memory,如果不熟悉的可以按照箭頭指示,點擊應用相對應的包名,就可以查看該應用內存情況,分析截圖如下
內存情況

Y君處理內存還是有稍許經驗的,不急不緩的亮出自己珍藏已久的內存分析三劍客:
LeakCanary MemZ喎?/kf/ware/vc/" target="_blank" class="keylink">vcnkgQW5hbHl6ZXIgVG9vbKOoTUFUo6k8L3N0cm9uZz4gPHN0cm9uZz5UcmFjZVZpZXc8L3N0cm9uZz4gPHN0cm9uZz7Ex8O0ztLDx7+qyry31s72zsrM4rP21NrExMDvsMkgLEFyZSBZb3UgUmVhZHk/IEdvITwvc3Ryb25nPg0KPGgzIGlkPQ=="leakcanary的使用方法">LeakCanary的使用方法

LeakCanary的GitHub地址
工具介紹:LeakCanary是Square開源的一個內存洩露自動探測神器,它是一個Android和Java的內存洩露檢測庫,可以大幅度減少了開發中遇到的OOM問題,對於安卓開發者來說,無疑是個福音。
GitHub裡邊介紹的已經很詳細了,我這裡也簡短的介紹一下使用方法!
在項目的build.gradle文件添加:

 dependencies {
   debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4-beta2'
   releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta2'
   testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta2'
 }

在Application裡邊初始化

public class ExampleApplication extends Application {

  @Override public void onCreate() {
    super.onCreate();
    LeakCanary.install(this);
  }
}

當正常接入的情況下,測試應用出現內存不足的時候會接受到通知,截圖如下

Leakcanary接受到正常通知

但是Y君的這個bug出現這種分析,沒有接到通知,截圖如下

Leakcanary接受不到通知

Leakcanary是的主要優勢就在於自動化過早的發覺內存洩露、配置簡單、抓取貼心,缺點在於還存在一些bug,不過正常使用百分之九十情況是OK的,然後我就成了那百分之十,具體問題我也不清楚,但是不妨礙這是一個很好的檢查工具。

Memory Analyzer Tool(MAT)的使用方法

MAT獨立版內存檢測工具下載

工具介紹:MAT(Memory Analyzer Tool)工具在分析 大內存的dump文件時,可以非常直觀的看到各個對象在堆空間中所占用的內存大小、類實例數量、對象引用關系、利用OQL對象查詢,以及可以很方便的找出對象GC Roots的相關信息,當然最吸引人的還是能夠快速為開發人員生成內存洩露報表,方便定位問題和分析問題。

測試Demo:我寫了一個Demo來模擬當時我遇到的情況!讓計時器一直發送消息到Handler刷新時間,代碼如下

 private void getCurrentTime() {
        //為了測試更加明顯
        new Thread() {

            @Override
            public void run() {
                super.run();
                while (flag) {
//                    SystemClock.sleep(1000);
                    long endTime = System.currentTimeMillis();
                    long time = endTime - mStartTime;
                    String result = new SimpleDateFormat("mm:ss").format(new Date(time));
                    Message message = handler.obtainMessage();
                    message.what = MessageConstants.UPDATETIMEFLAG;
                    mFinallyTime = result;//為了跳轉攜帶數據
                    message.obj = result;
                    handler.sendMessage(message);
                }
            }
        }.start();
    }
步驟一:我只講Android Studio下如何抓取內存使用的情況,點擊左上角的箭頭提示,會抓取你相對應的位置的內存使用情況,如圖4
這裡寫圖片描述 步驟二:稍等一會,生成的文件會出現在captures中,然後選擇文件,點擊右鍵轉換成標准的hprof文件,就可以在MAT中打開了。
這裡寫圖片描述
再次我解釋一下,MAT分兩種類型,一種是用於Eclispse插件版,一種是獨立版,因為我們用是Android Studio所以只能使用用獨立版的MAT. 步驟三:在MAT中打開抓取到的文件後,截圖如下
這裡寫圖片描述
MAT中提供了非常多的功能,這裡我們只要學習幾個最常用的就可以了。上圖最中央的那個餅狀圖展示了最大的幾個對象所占內存的比例,這張圖中提供的內容並不多,我們可以忽略它。
圖片中紅色框有使我們經常使用的模塊,它們的職責分別是: Histogram可以列出內存中每個對象的名字、數量以及大小。 Dominator Tree會將所有內存中的對象按大小進行排序,並且我們可以分析對象之間的引用結構。

 

  現在點擊Dominator Tree,截圖如下:

  

Dominator Tree 的分析

 

  這張圖包含的信息非常多,我來帶著大家一起解析一下。首先Retained Heap表示這個對象以及它所持有的其它引用(包括直接和間接)所占的總內存,因此從上圖中看,前兩行的Retained Heap是最大的,我們分析內存洩漏時,內存最大的對象也是最應該去懷疑的。

  另外大家應該可以注意到,在每一行的最左邊都有一個文件型的圖標,這些圖標有的左下角帶有一個紅色的點,有的則沒有。帶有紅點的對象就表示是可以被GC Roots訪問到的,根據上面的講解,可以被GC Root訪問到的對象都是無法被回收的。那麼這就說明所有帶紅色的對象都是洩漏的對象嗎?當然不是,因為有些對象系統需要一直使用,本來就不應該被回收。我們可以注意到,上圖當中所有帶紅點的對象最右邊都有寫一個System Class,說明這是一個由系統管理的對象,並不是由我們自己創建並導致內存洩漏的對象。

  那麼上圖中就無法看出內存洩漏的原因了嗎?確實,內存洩漏本來就不是這麼容易找出的,我們還需要進一步進行分析。上圖當中,除了帶有System Class的行之外,最大的就是第一行的MessageQueue對象了,雖然MessageQueue對象現在不能被GC Roots訪問到,但不代表著Bitmap所持有的其它引用也不會被GC Roots訪問到。現在我們可以對著第二行點擊右鍵 -> Path to GC Roots -> exclude weak references,為什麼選擇exclude weak references呢?因為弱引用是不會阻止對象被垃圾回收器回收的,所以我們這裡直接把它排除掉,結果如下圖所示:

  

結果1

 

  最終我們找到了罪魁禍首,開啟的很多個線程,while死循環沒有停止,我跳轉的時候也沒把循環關掉,所以有這麼多的Thread。

總結: 這大概就是MAT工具最常用的一些用法了,當然這裡還要提醒大家一句,工具是死的,人是活的,MAT也沒有辦法保證一定可以將內存洩漏的原因找出來,還是需要我們對程序的代碼有足夠多的了解,知道有哪些對象是存活的,以及它們存活的原因,然後再結合MAT給出的數據來進行具體的分析,這樣才有可能把一些隱藏得很深的問題原因給找出來。

 

TraceView的使用方法

借鑒了許多關於TraceView的分析,發現都是抄來抄去,最終都是一種解決辦法,不是針對各種問題解決問題,針對我這次碰到的這個問題,我慢慢琢磨了這麼工具的使用,發現直接可以分析出具體那個方法占用CPU的時間,個人認為從CPU角度思考內存優化,可以考慮使用這個工具來分析。
如何使用打開DDMS,然後如圖
這裡寫圖片描述
先按下Start Method Profiling(箭頭1標的位置),然後過一會可以按Stop Method Profiling,然後出現這種跟答題卡一樣的,我們只看下部分的分析
這裡寫圖片描述
顯而易見,分析Intel Cpu Time 屬性,點擊它按照從大到小的排序後,我們清晰發現run()方法居然占了93%的CPU運行內存,並且直接具體到哪一個類裡邊的方法。剩下的一些屬性估計有用,在這裡我也就不一一介紹了!如果你想詳細了解,點擊文章最後的參考鏈接即可。

解決問題(How)

通過這三種方法分析的分析結果:
1. LeakCanary反饋的信息沒有,無法分析
2. Memory Analyzer Tool(MAT)反饋的信息是MainAcitity中創建了很多的Thread,可以直接分析到死循環的毛病
3. TraceView通過CPU的使用情況非常直觀的顯示出,MainAcitivity中的run()方法占用95%的使用,干淨利索的分析出問題的所在

最後解決辦法:加1s的sleep時間,A跳轉到B頁面的時候,關掉循環!!

總結

文章也寫到了最後:
如果遇到卡頓問題的時候,推薦分析的步驟:
1. 先用Memory產看內存使用情況
2. 在用LeakCanary看是否能直接分析出那一個類出的錯誤
3. 如果LeakCanary分析的步驟不夠清晰,導出文件用MAT具體分析
4. 如果在MAT你也沒有檢查出哪裡出的錯誤,可以嘗試TraceView來分析內存使用情況,因為他可以具體到哪一個方法。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved