編輯:關於Android編程
上一篇文章總結的布局優化的問題,如果對布局優化不是很熟悉的,可以看一下Android Studido下的應用性能優化總結–布局優化 , 這周一直籌劃總結一下內存優化的問題,因為現在對於應用優化的文章很多,但是還是想完善一下才想分享這篇文章的,我會從項目中遇到的一個問題,通過解決問題的過程來分享知識,希望大家有所收獲。
“A small leak will sink a great ship.” - Benjamin Franklin
小樓不修補,大船也會翻。——本傑明 富蘭克林
由於出現卡頓現象,大部分都出自內存的問題上,所以我們開始分析自己應用的內存使用情況,但是問題來了,用什麼工具查看應用的內存使用情況?
因為以前Ecliplse的內存查看略顯繁瑣,而且Goole推出的新的開發工具Android Studio,有很多我們方便我們安卓開發程序猿調試和分析問題,在這裡我就介紹一下Android Studio中的內存分析工具Memory,如果不熟悉的可以按照箭頭指示,點擊應用相對應的包名,就可以查看該應用內存情況,分析截圖如下
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);
}
}
當正常接入的情況下,測試應用出現內存不足的時候會接受到通知,截圖如下
但是Y君的這個bug出現這種分析,沒有接到通知,截圖如下
Leakcanary是的主要優勢就在於自動化過早的發覺內存洩露、配置簡單、抓取貼心,缺點在於還存在一些bug,不過正常使用百分之九十情況是OK的,然後我就成了那百分之十,具體問題我也不清楚,但是不妨礙這是一個很好的檢查工具。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現在點擊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呢?因為弱引用是不會阻止對象被垃圾回收器回收的,所以我們這裡直接把它排除掉,結果如下圖所示:
最終我們找到了罪魁禍首,開啟的很多個線程,while死循環沒有停止,我跳轉的時候也沒把循環關掉,所以有這麼多的Thread。
總結: 這大概就是MAT工具最常用的一些用法了,當然這裡還要提醒大家一句,工具是死的,人是活的,MAT也沒有辦法保證一定可以將內存洩漏的原因找出來,還是需要我們對程序的代碼有足夠多的了解,知道有哪些對象是存活的,以及它們存活的原因,然後再結合MAT給出的數據來進行具體的分析,這樣才有可能把一些隱藏得很深的問題原因給找出來。
借鑒了許多關於TraceView的分析,發現都是抄來抄去,最終都是一種解決辦法,不是針對各種問題解決問題,針對我這次碰到的這個問題,我慢慢琢磨了這麼工具的使用,發現直接可以分析出具體那個方法占用CPU的時間,個人認為從CPU角度思考內存優化,可以考慮使用這個工具來分析。
如何使用打開DDMS,然後如圖
先按下Start Method Profiling(箭頭1標的位置),然後過一會可以按Stop Method Profiling,然後出現這種跟答題卡一樣的,我們只看下部分的分析
顯而易見,分析Intel Cpu Time 屬性,點擊它按照從大到小的排序後,我們清晰發現run()方法居然占了93%的CPU運行內存,並且直接具體到哪一個類裡邊的方法。剩下的一些屬性估計有用,在這裡我也就不一一介紹了!如果你想詳細了解,點擊文章最後的參考鏈接即可。
通過這三種方法分析的分析結果:
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來分析內存使用情況,因為他可以具體到哪一個方法。
先來看看效果:圖片切分很多份,點擊交換拼成一張完整的;這樣關卡也很容易設計,3 3;4 4;5 5;6 6;一直下去加了個切換動畫,效果還是不錯的,其實游戲就是自定義了一
Android 應用安裝過程:首先一個android項目,然後編譯和打包,將.java文件編譯為.class,.class編譯為.dex,將所有文件打包為一個apk,只編
最近瞄到一個小項目….Yalantis/Context-Menu.Android打開這個項目,我只想看看那個動態展開的menu是怎麼實現的.忽
在上一篇文章中,我們詳細分析了android是如何解析藍牙反饋上來的搜索到的設備信息,本文將會繼續分析這些信息到了上層之後是如何處理。 8、inquiry result引