好文推薦——系列文:
1.? 背景:Android App優(yōu)化, 要怎么做?
3.? Android App優(yōu)化之提升你的App啟動(dòng)速度之理論基礎(chǔ)
4.? Android App優(yōu)化之提升你的App啟動(dòng)速度之實(shí)例挑戰(zhàn)
5.? Android App優(yōu)化之Layout怎么擺
8.? Android App優(yōu)化之內(nèi)存優(yōu)化
10.??Android App優(yōu)化之如何高效網(wǎng)絡(luò)請(qǐng)求
1 簡介

1.1 官方工具
??? 一般來說, 學(xué)習(xí)一門新的技術(shù), 最應(yīng)該做的就是閱讀其官方文檔, 那是最權(quán)威的。Android本身給我們提供了很多App性能測(cè)試和分析工具, 而且大部分都集成到Android Studio或DDMS中, 非常方便使用。
1.1.1 StrictMode
· 說明
????????顧名思義, "嚴(yán)格模式", 主要用來限制應(yīng)用做一些不符合性能規(guī)范的事情. 一般用來檢測(cè)主線程中的耗?? 時(shí)操作和阻塞. 開啟StrictMode后, 如果線程中做一些諸如讀寫文件, 網(wǎng)絡(luò)訪問等操作, 將會(huì)在Log console輸出一些警告, 警告信息包含Stack Trace來顯示哪個(gè)地方出了問題.
· 文檔
????o?https://developer.android.com/reference/android/os/StrictMode.html
· 作用
????o 主要用來做主線程優(yōu)化分析
1.1.2 Systrace
· 說明
? ????Systrace是一個(gè)收集和檢測(cè)時(shí)間信息的工具,它能顯示CPU和時(shí)間被消耗在哪兒了,每個(gè)進(jìn)程和線程都在其CPU時(shí)間片內(nèi)做了什么事兒.而且會(huì)指示哪個(gè)地方出了問題,以及給出Fix建議.
? ????其以trace文件(html)的方式記錄.可以直接用Chrome瀏覽器打開查看.界面如下:

· 文檔
????o?https://developer.android.com/studio/profile/systrace.html
????o?https://developer.android.com/studio/profile/systrace-walkthru.html
????o?https://developer.android.com/studio/profile/systrace-commandline.html?hl=fy
· 作用
????o 作用很多,個(gè)人主要用來分析UI的繪制時(shí)間,結(jié)合Hierarchy Viewer來提升UI性能.
????o 也可以用來發(fā)現(xiàn)耗時(shí)操作.
1.1.3 HierarchyViewer
· 說明
? ????Hierarchy Viewer提供了一個(gè)可視化的界面來觀測(cè)布局的層級(jí),讓我們可以優(yōu)化布局層級(jí),刪除多余的不必要的View層級(jí),提升布局速度.

????????有必要說明下的是:
????????上圖紅框標(biāo)出的三個(gè)點(diǎn)是關(guān)鍵分析數(shù)據(jù). 左起依次代表View的Measure, Layout和Draw的性能. 另外顏色表示該View的該項(xiàng)時(shí)間指數(shù), 分為:
????* 綠色, 表示該View的此項(xiàng)性能比該View Tree中超過50%的View都要快.
????* 黃色, 表示該View的此項(xiàng)性能比該View Tree中超過50%的View都要慢.
????* 紅色, 表示該View的此項(xiàng)性能是View Tree中最慢的.
· 文檔
????o?https://developer.android.com/studio/profile/hierarchy-viewer.html
????o?https://developer.android.com/studio/profile/hierarchy-viewer-walkthru.html
????o?https://developer.android.com/studio/profile/hierarchy-viewer-setup.html
????o?https://developer.android.com/studio/profile/optimize-ui.html#HierarchyViewer
· 作用
????o 用來做View層級(jí)分析,可以分析出View Tree中的性能阻塞點(diǎn),以便對(duì)癥下藥,提升布局性能.
??? ????Hierarchy Viewer需要Root的機(jī)器(產(chǎn)品機(jī)沒有開啟ViewServer)才可以執(zhí)行??梢允褂?a target="_blank" rel="nofollow">第三方的開源的ViewServer來協(xié)助我們?cè)谖碦oot的機(jī)器上使用Hierarchy Viewer分析.
1.1.4 TraceView——方法耗時(shí)分析
· 文檔
????o?https://developer.android.com/studio/profile/traceview.html
????o?https://developer.android.com/studio/profile/traceview-walkthru.html
· 作用
????o 分析方法調(diào)用棧以及其執(zhí)行時(shí)間,優(yōu)化方法執(zhí)行.
1.1.5 MemoryMonitor——內(nèi)存監(jiān)控
· 說明
? ????內(nèi)存使用檢測(cè)器,可以實(shí)時(shí)檢測(cè)當(dāng)前Application的內(nèi)存使用和釋放等信息,并以圖形化界面展示。

· 文檔
????o?https://developer.android.com/studio/profile/am-memory.html
????o?https://developer.android.com/studio/profile/heap-viewer-walkthru.html
????o?https://developer.android.com/studio/profile/allocation-tracker-walkthru.html
· 作用
????o 用來做內(nèi)存分析,內(nèi)存泄露排查的不二之選.可以結(jié)合heap viewer, allocation tracker來分析.
????o 可以導(dǎo)出hprof文件結(jié)合第三方的MAT工具分析泄露點(diǎn).
1.1.6 OtherMonitor
· 說明
? ????Android Studio的Monitor還提供了其他三個(gè)Motinor --- CPU, GPU,Network.
· 文檔
????o?https://developer.android.com/studio/profile/am-cpu.html
????o?https://developer.android.com/studio/profile/am-gpu.html
????o?https://developer.android.com/studio/profile/am-network.html
· 作用
????o 分別用來跟蹤監(jiān)測(cè)CPU,GPU和Network的使用極其變化,可以作為網(wǎng)絡(luò)優(yōu)化,流量優(yōu)化和渲染優(yōu)化等的一個(gè)指導(dǎo). (個(gè)人并不常用到~)
1.1.7 其他
??? Android的開發(fā)者模式中也提供了較多的用來監(jiān)測(cè)性能的選項(xiàng), 可以用下:

1.2 第三方工具
???? 以下工具全部開源
1.2.1 Google的Battery Historian
· 說明
? ????Google出品, 通過Android系統(tǒng)的bug report文件來做電量使用分析的工具.
·? 文檔
????o?https://github.com/google/battery-historian
· 作用
????o 用來做電量使用分析.
1.2.2 網(wǎng)易的Emmagee
· 說明
????????針對(duì)Android App的CPU, 內(nèi)存, 網(wǎng)絡(luò), 電量等多項(xiàng)綜合的測(cè)試分析.
· 文檔
????o?https://github.com/NetEase/Emmagee
· 作用
????o 比官方工具更適合國人使用來做App的整體性能分析.
1.2.3 Square的leakcanary
· 說明
? ????Square出品, 必屬精品.類似于App探針的內(nèi)存泄露監(jiān)測(cè)工具.
· 文檔
????o?https://github.com/square/leakcanary
· 作用
????o 集成到App中,用來做內(nèi)存問題預(yù)防最好不過了.
1.2.4 AndroidDevMetrics
· 說明
????????一個(gè)library, 用來檢測(cè)Activity生命周期執(zhí)行性能, Dagger2注入性能以及幀率性能的工具.
· 文檔
????o?https://github.com/frogermcs/AndroidDevMetrics
· 作用
????o 如果你的應(yīng)用使用的Dagger2,這個(gè)就比較必要了.
2 MemoryMonitor
(轉(zhuǎn)自)Android Studio Memory Monitor
http://blog.csdn.net/flyworkspace/article/details/54019812
2.1 使用方法
2.1.1 內(nèi)存鏡像
????????生成內(nèi)存鏡像,當(dāng)從圖中發(fā)現(xiàn)內(nèi)存使用較高時(shí),點(diǎn)擊小卡車圖標(biāo),可以主動(dòng)觸發(fā)GC。當(dāng)應(yīng)用內(nèi)存使用很高,并且存在很嚴(yán)重的內(nèi)存泄露時(shí),點(diǎn)擊該按鈕后的效果并不明顯,內(nèi)存并沒有降低或者降低的很少。點(diǎn)擊"Dump Java Heap"圖標(biāo)稍等片刻,會(huì)生成該應(yīng)用的內(nèi)存快照。如圖

????? Total Count:內(nèi)存中該類對(duì)象個(gè)數(shù)。
????? Heap Count:堆內(nèi)存中該類對(duì)象個(gè)數(shù)。
????? Sizeof:每個(gè)對(duì)象的大小(如果為0,則大小不固定)。
????? Shallow size:對(duì)象本身占有內(nèi)存大小。
????? Retained Size:釋放該對(duì)象后,節(jié)省的內(nèi)存大小。
????????其中,Retained Size之所以比Shallowsize大的原因是,該對(duì)象釋放后,會(huì)引起其他對(duì)象的回收。 例如,某個(gè)對(duì)象被回收后: 該對(duì)象引用的其他對(duì)象也會(huì)被回收, 該對(duì)象A被另一對(duì)象B強(qiáng)引用后,之前對(duì)象B因?yàn)閺?qiáng)引用該對(duì)象A而沒有被回收,現(xiàn)在該對(duì)象A被回收后,若對(duì)象B強(qiáng)引用的其他對(duì)象都已被回收,則對(duì)象B也會(huì)被回收。
????優(yōu)化內(nèi)存:
????????點(diǎn)擊Class Name中的類名,查看其所有實(shí)例(Instance),分析實(shí)例中參數(shù)所占用的內(nèi)存。根據(jù)Retaine Size排序,查找Instance中Depth較小的實(shí)例或者參數(shù),在代碼中找到相應(yīng)的位置,查看內(nèi)存占用是否合理。
????判斷內(nèi)存泄露的步驟:
????????從Total Count入手。該類的對(duì)象數(shù)量不對(duì)。
????? 很多對(duì)象只可能存在1個(gè),若存在多個(gè),則可能存在泄露。例如MainActivity的數(shù)量為2。又或者由于單例的使用不規(guī)范而導(dǎo)致創(chuàng)建多個(gè)“單例”對(duì)象。
????? 某個(gè)對(duì)象已經(jīng)不再使用,而其還在內(nèi)存中顯示。例如LoginActivity已經(jīng)退出了,其數(shù)量為1。
????????Memory Monitor只提供了內(nèi)存信息,如需詳細(xì)信息,可以通過android studio的Captures(View—–Tool window—–Captures)欄,右鍵點(diǎn)擊快照文件,Export to standard .hprof將堆快照(Heap Snapshot)轉(zhuǎn)換成通用的hprof文件,之后可以通過其他內(nèi)存分析工具打開,例如MAT。
2.1.2 跟蹤內(nèi)存分配(Allocation tracker)
????????點(diǎn)擊“Start Allocation Tracking”開始監(jiān)聽內(nèi)存的分配情況,再次點(diǎn)擊,監(jiān)聽完成,生成報(bào)告。該報(bào)告顯示這段時(shí)間內(nèi),內(nèi)存的分配情況。
2.1.3 小結(jié)
????????2.1是從內(nèi)存的靜態(tài)信息中分析,是某一個(gè)點(diǎn)的內(nèi)存使用情況。2.2是跟蹤某一段時(shí)間內(nèi)內(nèi)存的分配情況,是個(gè)過程跟蹤。分析內(nèi)存可以相結(jié)合,例如,再進(jìn)行某個(gè)操作前,執(zhí)行2.1導(dǎo)出靜態(tài)內(nèi)存信息,在開啟2.2開始跟蹤內(nèi)存的分配。當(dāng)執(zhí)行完操作的時(shí)候,關(guān)閉內(nèi)存分配的跟蹤,再次執(zhí)行2.1的,導(dǎo)出操作某個(gè)流程后的靜態(tài)信息。將2.1的兩個(gè)靜態(tài)表結(jié)合2.2的內(nèi)存分配動(dòng)態(tài)過程一起分析。
2.2 分析樣例
2.2.1 占用內(nèi)存分析樣例
????????打開某應(yīng)用后,切換幾個(gè)頁面,內(nèi)存飛速上漲。這只是一個(gè)極端例子,有很多app,隨著用的時(shí)間越長,內(nèi)存也是一直在升高。

????????根據(jù)2.1的方法,生成內(nèi)存鏡像。

????????查找可疑的對(duì)象,這個(gè)過程是逐個(gè)分析的過程,例如byte[]其實(shí)是其他對(duì)象的某個(gè)參數(shù),很多本質(zhì)上都是byte[],例如Bitmap中mBuffer也是byte[],當(dāng)內(nèi)存中有很多Bitmap的時(shí)候,byte[]也會(huì)很高。所以byte[]不是我們重點(diǎn)關(guān)注對(duì)象,如果真的是因?yàn)锽itmap(或者其他類)多而造成的byte[]高,那么下面肯定會(huì)有該類也會(huì)占用很高內(nèi)存。
????????繼續(xù)分析下一個(gè)HashMap$HashMapEntry。點(diǎn)擊它后,在Instance欄中,看到其實(shí)例很多,先從占用大的實(shí)例入手。

????????例如99=這個(gè),點(diǎn)擊它后ReferenceTree顯示如下:

????????得知這個(gè)HashMap是ReuseThumbnail…類中ReuseThumbnailManager的REUSE_BITMAPS。在代碼中查看其大小是否合理。本例中REUSE_BITMAPS參數(shù)是static參數(shù),其類型是HashMap,查看邏輯,看其是否正常。
????????再看其他參數(shù),逐個(gè)分析其內(nèi)存占用是否正常。
????????分析內(nèi)存是個(gè)逐步的過程,一個(gè)問題解決后,再次循環(huán)這些步驟。有時(shí)候雖然列表中顯示很多對(duì)象占用內(nèi)存很高,有可能是同一個(gè)參數(shù)導(dǎo)致的,所以一個(gè)問題解決后,有可能有一系列參數(shù)占用高的情況會(huì)消失。就比如如果高內(nèi)存bitmap的優(yōu)化后,byte[]也很降低很多,其他參數(shù)也有可能會(huì)降低很多。
2.2.2 跟蹤內(nèi)存分配分析樣例
????????3.1是從靜態(tài)內(nèi)存信息中分析內(nèi)存的使用,現(xiàn)在按照2.2從動(dòng)態(tài)過程中跟蹤內(nèi)存的分配。

????????生成報(bào)告如下:

????????查看Size最大的一個(gè)Thread.

????????可以看到調(diào)用過程,從NewDisplayRunnale(執(zhí)行了636次)調(diào)用了BitmapDecoder的decode方法(執(zhí)行了135次),從代碼中分析過程是否合理。
2.2.3 內(nèi)存泄露分析樣例
????????對(duì)于android的內(nèi)存泄露,一般監(jiān)測(cè)Activity的泄露居多,例如LeakCanary默認(rèn)也是監(jiān)測(cè)Activity是否泄露。
????????現(xiàn)寫一個(gè)demo,故意造成內(nèi)存泄露作為分析樣例。
public class MyActivity extends Activity{
???@Override
???public void onCreate(Bundle savedInstanceState) {
??????? super.onCreate(savedInstanceState);
??????? setContentView(R.layout.main);
??????? new TestThread().start();
???}
???class TestThread extends Thread{
??????? @Override
??????? public voidrun() {
???????????super.run();
??????????? try{
??????????????? Thread.sleep(10 * 60 * 1000);
??????????? }catch(InterruptedException e) {
??????????????? e.printStackTrace();
??????????? }
??????? }
???}
}
????????當(dāng)進(jìn)入MyActivity點(diǎn)擊回退,重復(fù)多次。按照2.1方法獲取內(nèi)存鏡像。

????????看到MyActivity的實(shí)例數(shù)量為17個(gè)。在右邊的Analyzer Tasks欄中:

????????一般引起Activity泄露是由于其Context被強(qiáng)引用導(dǎo)致的。

????????MyActivity的context參數(shù)被TestThread引用了。所以在activity的銷毀的時(shí)候,由于TestThread還引用著MyActivity,所以阻止了MyActivity被釋放,因而導(dǎo)致內(nèi)存泄露。
2.3 性能數(shù)據(jù)采集

3 DDMS
http://www.cnblogs.com/gaobig/p/5029381.html
????????Android Studio開發(fā)工具中,打開DDMS,具體的方式如圖:

??? 打開之后的窗口如圖:

??? 查看進(jìn)程中的線程:

??? 查看內(nèi)存信息:

3.1? Traceview
Android學(xué)習(xí)之Android studio TraceView和lint工具的使用詳解
http://blog.csdn.net/qq_16131393/article/details/51172488
3.1.1 使用方法
??? 打開AndroidDevice Monitor,這個(gè)大家都知道:

????1. 選擇你要調(diào)試的進(jìn)程。
????2. 點(diǎn)擊start mothod profiling,待圖標(biāo)變黑。
????3. 選擇sample base profiling
????這里需要解釋一下:
????Trace base profiling
????????整體監(jiān)聽,項(xiàng)目中所有方法都會(huì)監(jiān)聽,資源消耗比較大。
????sample base profiling
????????抽樣監(jiān)聽,以指定的頻率進(jìn)行抽樣調(diào)查,一般不要超過5s,需要較長時(shí)間獲取準(zhǔn)確的樣本數(shù)據(jù)。
????再次點(diǎn)擊start mothod profiling,就會(huì)生成檢測(cè)樣本。
????效果如下:

????????上部分為時(shí)間軸,x軸表示時(shí)間,黑色區(qū)域可放大,每個(gè)區(qū)域代表每個(gè)方法的執(zhí)行時(shí)間。y軸表示每一個(gè)獨(dú)立線程。
????????下部分Name為你所選擇的顏色區(qū)塊所代表的性能分析。不同的顏色,代表不同的方法,顏色長度代表占用時(shí)間。
????????屬性介紹:
????Incl cpu time:某方法占用cpu時(shí)間(父+子)
????Excl cpu time:某方法本身占用cpu時(shí)間(父)
????Incl Real time:某方法真正執(zhí)行時(shí)間(父+子)
????Excl Real time:某方法自身執(zhí)行時(shí)間(父)
????????當(dāng)然還有相應(yīng)所占百分比,不過多介紹。
????????還有Calls+RecurCall調(diào)用次數(shù)+遞歸調(diào)用次數(shù)
????????還有比較重要的:
????cpu time/call:平均每次調(diào)用占用cpu時(shí)間。
????real time/call:平均每次調(diào)用所執(zhí)行的時(shí)間。
????我覺得這個(gè)參數(shù)很具有參考性。

????????打開每個(gè)方法,會(huì)顯示Paents和children(即父方法和子方法),以及分別所占用時(shí)間。
· 說明
? ????一個(gè)圖形化的工具,用來展示和分析方法的執(zhí)行時(shí)間.

3.1.2 數(shù)據(jù)采集

3.2 Heap Viewer
3.2.1 HeapViewer面板

??? ????按上圖的標(biāo)記順序按下,我們就能看到內(nèi)存的具體數(shù)據(jù),右邊面板中數(shù)值會(huì)在每次GC時(shí)發(fā)生改變,包括App自動(dòng)觸發(fā)或者你來手動(dòng)觸發(fā)。
3.2.2 詳情


??? 下面是每一個(gè)對(duì)象都有的列名含義:

??? ????當(dāng)我們點(diǎn)擊某一行時(shí),可以看到如下的柱狀圖:

????????橫坐標(biāo)是對(duì)象的內(nèi)存大小,這些值隨著不同對(duì)象是不同的,縱坐標(biāo)是在某個(gè)內(nèi)存大小上的對(duì)象的數(shù)量。
3.2.3 HeapViewer的使用
??? ????我們說HeapViewer適合發(fā)現(xiàn)內(nèi)存泄漏的問題,那你知道何為內(nèi)存泄漏么?
????內(nèi)存泄漏
????英文名:Memory Leaks
????標(biāo)準(zhǔn)解釋:無用的單純,但是還是沒GC ROOT引用的內(nèi)存
????通俗解釋:該死不死的內(nèi)存
????檢測(cè)
????????那么如何檢測(cè)呢?Heap Viewer中的數(shù)值會(huì)自動(dòng)在每次發(fā)生GC時(shí)會(huì)自動(dòng)更新,那么我們是等著他自己GC么?小弟不才,剛開始我就是這么一直等啊等,由于GC的時(shí)機(jī)是系統(tǒng)把握的,所以很不好把握,既然我們是來看內(nèi)存泄漏,那么我們?cè)谛枰獧z測(cè)內(nèi)存泄漏的用例執(zhí)行過后,手動(dòng)GC下,然后觀察data object一欄的total size(也可以觀察HeapSize/Allocated內(nèi)存的情況),看看內(nèi)存是不是會(huì)回到一個(gè)穩(wěn)定值,多次操作后,只要內(nèi)存是穩(wěn)定在某個(gè)值,那么說明沒有內(nèi)存溢出的,如果發(fā)現(xiàn)內(nèi)存在每次GC后,都在增長,不管是慢增長還是快速增長,都說明有內(nèi)存泄漏的可能性。
????實(shí)例
????先來看3個(gè)圖:
????1.剛打開首頁,手動(dòng)GC一下:

????????2.首頁到詳情頁10遍,最后回到首頁,手動(dòng)GC一下,直到數(shù)值不再變化:

????????3.首頁到詳情頁10遍,最后回到首頁,手動(dòng)GC一下:

????????從data object一欄看到該類型的數(shù)值會(huì)在不斷增長,可能發(fā)生了內(nèi)存泄漏,而我們也可以從上面三個(gè)圖的標(biāo)紅部分來看,Allocated分別增加了2.418M和1.084M,而且你繼續(xù)這么操作下去,內(nèi)存依然是增長的趨勢(shì)。
3.2.4 數(shù)據(jù)采集

4 Emmagee
4.1 使用說明
????1、Emmagee是網(wǎng)易杭州研究院QA團(tuán)隊(duì)開發(fā)的一個(gè)簡單易上手的Android性能監(jiān)測(cè)小工具,主要用于監(jiān)控單個(gè)App的CPU,內(nèi)存,流量,啟動(dòng)耗時(shí),電量,電流等性能狀態(tài)的變化,且用戶可自定義配置監(jiān)控的頻率以及性能的實(shí)時(shí)顯示,并最終生成一份性能統(tǒng)計(jì)文件。
????2、操作完成后,從系統(tǒng)任務(wù)列表中選擇Emmagee,并停止測(cè)試,在”storage\sdcard0”下找到命名類似”Emmagee_TestResult_20140403210532.csv”的文件,打卡即為監(jiān)控的得到的數(shù)據(jù)。
????3、將csv數(shù)據(jù)拷貝到excel中生成圖表,即可清晰看到整個(gè)操作過程中cpu、內(nèi)存等關(guān)鍵數(shù)據(jù)的變化。
Android性能測(cè)試小工具Emmagee - 敵測(cè)漏師
http://blog.csdn.net/anlegor/article/details/22895993
APP性能測(cè)試工具Emmagee的使用總結(jié)
http://blog.csdn.net/chenrushui/article/details/51589995
http://www.cnblogs.com/jytian/p/6516170.html
4.2 性能數(shù)據(jù)采集

5 leakcanary
· 說明
? ????Square出品, 必屬精品,類似于App探針的內(nèi)存泄露監(jiān)測(cè)工具.
· 文檔
????o?https://github.com/square/leakcanary
· 作用
????o 集成到App中,用來做內(nèi)存問題預(yù)防最好不過了.
5.1 使用說明
LeakCanary使用指南(1)
http://blog.csdn.net/hmh0512/article/details/57053265?utm_source=tuicool&utm_medium=referral
????快速集成
????????第一步:在build.gradle中添加如下依賴:
dependencies {
????debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
????releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
????testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
}
????????第二步:在自己的Application(假設(shè)名為ExampleApplication)中添加如下代碼:
public class? ExampleApplication extends?Application {
????@Override?
? ??public void?onCreate()? {
? ??????super.onCreate();
? ??????if? (LeakCanary.isInAnalyzerProcess(this)) {
????????????// This process is dedicated to LeakCanary for heap analysis.
????????????// You should not init your app in this process.
? ??????????return;
????????}
????????LeakCanary.install(this);
????????// Normal app init code...
????}
}
????????到這里其實(shí)可以檢測(cè)到Activity的內(nèi)存泄露了,原理后面再說。以Debug模式運(yùn)行你的App,你可以看到,你App的圖標(biāo)后面跟著一個(gè)Leaks圖標(biāo),如下圖;而如果你以Release模式運(yùn)行,則沒有這個(gè)圖標(biāo)。

????測(cè)試使用
????????假裝你是測(cè)試人員,你開始各種點(diǎn)擊App,進(jìn)行測(cè)試。然后你有幸看到這樣一個(gè)彈框,如下圖。

????????你很好奇,然后點(diǎn)擊了彈框中間那個(gè)圖標(biāo),于是手機(jī)屏幕的左上角出現(xiàn)了你App的圖標(biāo),再下拉點(diǎn)擊那個(gè)圖標(biāo),或者從桌面上LeakCanary圖標(biāo)(跟在你App的圖標(biāo)屁股后面那個(gè))點(diǎn)進(jìn)去,你看到下圖。點(diǎn)擊+號(hào)可以展開,點(diǎn)擊-號(hào)收起。

????????內(nèi)存泄露往往發(fā)生在,生命周期較長的對(duì)象,直接或間接持有了生命周期較短的對(duì)象的強(qiáng)引用,導(dǎo)致了生命周期較短的對(duì)象不能及時(shí)釋放。
????????上圖已經(jīng)夠傻瓜式了,第一行表示生命周期較長的那個(gè)對(duì)象,圖中是AliPayModel這個(gè)類;第二行表示生命周期長的那個(gè)持有了一個(gè)什么樣的引用,圖中是mActivity;第三行表示生命周期較短的那個(gè)對(duì)象,圖中是SelectPayTypeActivity。
????????回去查看源碼,發(fā)現(xiàn)AliPayModel是個(gè)單例,在SelectPayTypeActivity中以AliPayModel.getInstance(this).XXX()的方式調(diào)用單例中的XXX()方法。于是AliPayModel通過mActivity持有了SelectPayTypeActivity.this的引用。SelectPayTypeActivity本來應(yīng)該在用戶退出這個(gè)頁面和進(jìn)入其他Activity(尤其是其他Activity層級(jí)較深時(shí))時(shí)釋放掉,但是單例的生命周期貫穿整個(gè)App,AliPayModel一直引用著SelectPayTypeActivity,導(dǎo)致SelectPayTypeActivity不能及時(shí)釋放,引發(fā)內(nèi)存泄露。
public class? AliPayModel extends?BasePayModel {
? ??private?Activity? mActivity;
? ??private?AliPayModel() {}
? ??private static? AliPayModel instance = new?AliPayModel();
? ??public static?AliPayModel? getInstance(Activity tag) {
????????instance.mActivity = tag;
? ??????return?instance;
????}
}
????????找到了原因,解決方法也呼之欲出。要么AliPayModel這個(gè)業(yè)務(wù)類不要定義成單例,要么mActivity由強(qiáng)引用改成軟引用或者弱引用。Java的強(qiáng)、軟、弱、虛四種引用的區(qū)別不在本文的討論范圍。
????發(fā)現(xiàn)開源組件中的內(nèi)存泄露
????????用上述方法,可以檢測(cè)出各種各樣的內(nèi)存泄露,包括:WebView導(dǎo)致的內(nèi)存泄露、資源未關(guān)閉導(dǎo)致的內(nèi)存泄露、非靜態(tài)匿名內(nèi)部類導(dǎo)致的內(nèi)存泄露、Handler導(dǎo)致的內(nèi)存泄露等等。
????????請(qǐng)看下圖,每次選擇圖片、上傳頭像時(shí)都會(huì)引發(fā)0.96M的內(nèi)存泄露!

????????再按圖索驥,發(fā)現(xiàn)罪魁禍?zhǔn)资菍⒁粋€(gè)Activity定義為static。表示不是很能理解這種神代碼。最讓人心中萬馬奔騰的是,它竟然有2600多個(gè)star!在這個(gè)項(xiàng)目的Issues中很多人反映內(nèi)存占用大、容易OOM、卡頓等,但是沒有人從技術(shù)層面去查找和分析原因,更遑論去閱讀源碼,都是直接拿來就用!

6 參考鏈接
Android App優(yōu)化之性能分析工具
http://m.itdecent.cn/p/da2a4bfcba68
Android開發(fā)調(diào)試必備-使用DDMS
http://blog.csdn.net/stzy00/article/details/46554529
Android內(nèi)存分析工具(二):DDMS
http://blog.csdn.net/berber78/article/details/47784007
Android性能專項(xiàng)測(cè)試之Heap Viewer工具
http://blog.csdn.net/itfootball/article/details/48734553
正確使用Android性能分析工具——TraceView
http://android.jobbole.com/78995/
Android性能專項(xiàng)測(cè)試之MemoryMonitor工具
http://blog.csdn.net/itfootball/article/details/48712595
Android性能優(yōu)化第(二)篇---Memory Monitor檢測(cè)內(nèi)存泄露
http://www.cnblogs.com/ldq2016/p/6628311.html
Android內(nèi)存與性能
http://blog.kamidox.com/android-memory-guide.html
Android系統(tǒng)性能調(diào)優(yōu)工具介紹
http://blog.csdn.net/innost/article/details/9008691/
Android開發(fā)——Android多進(jìn)程以及使用場景介紹
http://blog.csdn.net/seu_calvin/article/details/53932171
理解Android進(jìn)程創(chuàng)建流程
http://gityuan.com/2016/03/26/app-process-create/
LeakCanary使用指南(1)
http://blog.csdn.net/hmh0512/article/details/57053265?utm_source=tuicool&utm_medium=referral
利用LeakCanary來檢查Android內(nèi)存泄漏
http://m.itdecent.cn/p/0049e9b344b0
LeakCanary中文使用說明