Android性能優(yōu)化篇之內(nèi)存優(yōu)化--內(nèi)存優(yōu)化分析工具

image

引言

1. Android性能優(yōu)化篇之內(nèi)存優(yōu)化--內(nèi)存泄漏

2.Android性能優(yōu)化篇之內(nèi)存優(yōu)化--內(nèi)存優(yōu)化分析工具

3.Android性能優(yōu)化篇之UI渲染性能優(yōu)化

4.Android性能優(yōu)化篇之計(jì)算性能優(yōu)化

5.Android性能優(yōu)化篇之電量?jī)?yōu)化(1)——電量消耗分析

6.Android性能優(yōu)化篇之電量?jī)?yōu)化(2)

7.Android性能優(yōu)化篇之網(wǎng)絡(luò)優(yōu)化

8.Android性能優(yōu)化篇之Bitmap優(yōu)化

9.Android性能優(yōu)化篇之圖片壓縮優(yōu)化

10.Android性能優(yōu)化篇之多線(xiàn)程并發(fā)優(yōu)化

11.Android性能優(yōu)化篇之?dāng)?shù)據(jù)傳輸效率優(yōu)化

12.Android性能優(yōu)化篇之程序啟動(dòng)時(shí)間性能優(yōu)化

13.Android性能優(yōu)化篇之安裝包性能優(yōu)化

14.Android性能優(yōu)化篇之服務(wù)優(yōu)化

介紹

上一章講了內(nèi)存相關(guān)的知識(shí)和內(nèi)存泄漏的常見(jiàn)案例以及解決方法,我們寫(xiě)代碼的時(shí)候要注意避免。但是我們不可能完全避免出現(xiàn)內(nèi)存泄漏的情況,所以就要通過(guò)內(nèi)存分析工具來(lái)分析是否產(chǎn)生了內(nèi)存泄漏。主要講的工具有以下幾種:

Heap Snapshot
Heap Viewer
MAT
Allaction Tracking
TraceView
LeakCanary
Lint


下面我們就來(lái)一一講解這些工具的使用:

1.Heap Snapshot

Heap Snapshot 是 android Studio 中 Android Monitor中的一個(gè)分析Java堆內(nèi)存信息的工具,這邊我們就用上章中的單例導(dǎo)致內(nèi)存泄漏的例子來(lái)分析:

(1).Heap Dump啟動(dòng)

點(diǎn)擊圖中紅色框中的Dump Java Heap,就會(huì)dump 出java堆內(nèi)存信息文件(.hprof)


image1.png
(2).分析Heap Snapshot面板中的信息

android studio會(huì)自動(dòng)打開(kāi)hprof文件,我們這時(shí)候就可以來(lái)重點(diǎn)分析我們需要檢查的類(lèi)是否有內(nèi)存泄漏(必須要確定分析具體的類(lèi),比如我們分析MainActivity是否有內(nèi)存泄漏,可以反復(fù)的改變屏幕的方向,然后dump出堆信息)


image2.png

我們看到ClassName中可能數(shù)據(jù)太多,我們?cè)趺茨軌蚨ㄎ坏轿覀円治龅念?lèi)呢,可以選擇第二個(gè)紅色框中的選擇項(xiàng)來(lái)快的定位。


image4.png

我們選擇通過(guò)包來(lái)展示,這樣可以通過(guò)包名來(lái)快速定位。
image5.png

下面我們來(lái)分析下MainActivity是否有內(nèi)存泄漏。


image6.png

我們看到這里MainActivity有兩個(gè)實(shí)例且都有深度,也就是說(shuō)都被引用,根據(jù)Acitivity的生命周期原理,屏幕的旋轉(zhuǎn)會(huì)回收之前的Activity,然后創(chuàng)建一個(gè)新的Activity,另一個(gè)一個(gè)被回收或者等待被回收,所以MainActivity肯定存在內(nèi)存泄漏的問(wèn)題。這個(gè)需要結(jié)合下面的引用樹(shù)來(lái)看,但是這個(gè)太麻煩還不要用對(duì),下面我們將介紹更好的工具來(lái)分析,這邊只要知道我們分析的類(lèi)是否發(fā)生內(nèi)存泄漏就行了。


下面我們給出Snapshot中表中字段含意:

Class Name 板塊
    Total Count     內(nèi)存中該類(lèi)的對(duì)象個(gè)數(shù)
    Heap Count      堆內(nèi)存中該類(lèi)的對(duì)象個(gè)數(shù)
    Sizeof          物理大小
    Shallow size    該對(duì)象本身占有內(nèi)存大小
    Retained Size   釋放該對(duì)象后,節(jié)省的內(nèi)存大小

Instance 板塊

    depth           深度
    Shallow Size    對(duì)象本身內(nèi)存大小
    Dominating Size 管轄的內(nèi)存大小


2.Heap Viewer

Heap Viewer 是 Android Device Monitor 中的實(shí)時(shí)查看App分配的內(nèi)存大小和空閑內(nèi)存大小和發(fā)現(xiàn)內(nèi)存泄漏的工具。
使用條件:1.必須5.0以及以上的系統(tǒng),2.開(kāi)發(fā)者選項(xiàng)可用

使用步驟:
    1.打開(kāi)Android Device Monitor 
    2.點(diǎn)擊DDMS
    3.選中heap選項(xiàng)卡
    4.選中我們的項(xiàng)目
    5.點(diǎn)擊update heap
    6.點(diǎn)擊Cause GC
image7.png
下面解釋下Heap面板中表示的意思:
image8.png

A

    Heap Size   堆棧分配給App的內(nèi)存大小
    Allocated   已分配使用的內(nèi)存大小
    Free    空閑的內(nèi)存大小
    %Used   Allocated/Heap Size,使用率
    Objects 對(duì)象數(shù)量

B 中 Type 類(lèi)型

    free    空閑的對(duì)象
    data object 數(shù)據(jù)對(duì)象,類(lèi)類(lèi)型對(duì)象,最主要的觀(guān)察對(duì)象
    class object    類(lèi)類(lèi)型的引用對(duì)象
    1-byte array(byte[],boolean[])  一個(gè)字節(jié)的數(shù)組對(duì)象
    2-byte array(short[],char[])    兩個(gè)字節(jié)的數(shù)組對(duì)象
    4-byte array(long[],double[])   4個(gè)字節(jié)的數(shù)組對(duì)象
    non-Java object 非Java對(duì)象

B 中 表中列的表示意思

    Count   數(shù)量
    Total Size  總共占用的內(nèi)存大小
    Smallest    將對(duì)象占用內(nèi)存的大小從小往大排,排在第一個(gè)的對(duì)象占用內(nèi)存大小
    Largest 將對(duì)象占用內(nèi)存的大小從小往大排,排在最后一個(gè)的對(duì)象占用的內(nèi)存大小
    Median  將對(duì)象占用內(nèi)存的大小從小往大排,拍在中間的對(duì)象占用的內(nèi)存大小
    Average 平均值

當(dāng)我們點(diǎn)擊某一行時(shí),可以看到 C 的柱狀圖 ,表示 橫坐標(biāo)是對(duì)象的內(nèi)存大小,這些值隨著不同對(duì)象是不同的,縱坐標(biāo)是在某個(gè)內(nèi)存大小上的對(duì)象的數(shù)量

下面我們來(lái)發(fā)現(xiàn)有內(nèi)存泄漏的單例例子:
(1).旋轉(zhuǎn)屏幕前,我們看到已經(jīng)分配的內(nèi)存為814.617kb(手動(dòng)GC):


image9.png

(2).旋轉(zhuǎn)屏幕后,我們看到已經(jīng)分配的內(nèi)存為956.891kb(手動(dòng)GC):


image10.png

我們對(duì)比前后的兩次發(fā)現(xiàn)有內(nèi)存不能被回收,也就是說(shuō)旋轉(zhuǎn)屏幕導(dǎo)致內(nèi)存泄漏了。這個(gè)工具沒(méi)法具體定位到內(nèi)存泄漏的位置。

補(bǔ)充:Heap Viewer不光可以用來(lái)檢測(cè)是否有內(nèi)存泄漏,對(duì)于內(nèi)存抖動(dòng),我們也可以用該工具檢測(cè),因?yàn)閮?nèi)存抖動(dòng)的時(shí)候,會(huì)頻繁發(fā)生GC,這個(gè)時(shí)候我們只需要開(kāi)啟Heap Viewer,觀(guān)察數(shù)據(jù)的變化,如果發(fā)生內(nèi)存抖動(dòng),會(huì)觀(guān)察到數(shù)據(jù)在段時(shí)間內(nèi)頻繁更新


3.MAT

全稱(chēng)為Memory Analyzer Tool,一款詳細(xì)分析Java堆內(nèi)存的工具,該工具非常強(qiáng)大,為了使用該工具,我們需要hprof文件。但是該文件不能直接被MAT使用,需要進(jìn)行一步轉(zhuǎn)化,可以使用hprof-conv命令來(lái)轉(zhuǎn)化,但是Android Studio可以直接轉(zhuǎn)化.

下面我們就來(lái)那Heap Snapshot 中的hprof來(lái)分析:

(1).轉(zhuǎn)換hprof文件


image11.png

(2).使用Memory Analyzer Tool工具打開(kāi)hprof文件


image12.png

工具會(huì)自動(dòng)生成一個(gè)可疑的內(nèi)存泄漏,其實(shí)這里對(duì)我們用處不大,我們主要分析overView選項(xiàng)卡。


image13.png

我們看到這里給出了一些基本的數(shù)據(jù)我大對(duì)象的圖,我們主要分析下面的Actions中的三個(gè)工具:
Histogram

主要是列出每個(gè)類(lèi)中對(duì)象,點(diǎn)擊看下:


image14.png

我們看到這邊的對(duì)象有點(diǎn)多,我們選擇按照包來(lái)顯示,或者通過(guò)regex來(lái)篩選。
image15.png

找到我們要分析的類(lèi),選擇ListObject中的with incoming references,來(lái)顯示引用MainActivity的類(lèi)。
image16.png

我們看到這邊有兩個(gè)地方引用了MainActivity,然后現(xiàn)在圖中的選項(xiàng),排除所有的soft,weak,phantom引用,看看當(dāng)前的被什么引用。我們來(lái)看下兩個(gè)結(jié)果:

image17.png
image18.png

我們看到一個(gè)被CommonUtil引用,導(dǎo)致內(nèi)存泄漏,一個(gè)被InputMethodManger引用,導(dǎo)致內(nèi)存泄漏,第二個(gè)是系統(tǒng)輸入法的bug,而第一個(gè)是我們自己寫(xiě)的,如果列表中顯示很多我們只能一一分析。

上面是分析一個(gè)hprof來(lái)看,可能有時(shí)也看不出來(lái),那么我們可以通過(guò)兩個(gè)hprof來(lái)對(duì)比分析。

對(duì)比分析

(1).將兩個(gè)hprof文件添加到工具中
(2).將兩個(gè)hprof文件添加到對(duì)比列表中


image19.png

(3).對(duì)比分析


image20.png
image21.png

我們看到經(jīng)過(guò)旋轉(zhuǎn)操作,MainActivity有兩個(gè),所以這邊肯定發(fā)生了內(nèi)存泄漏,那到底是什么引起內(nèi)存泄漏的呢?下面的分析步驟就和上面單獨(dú)分析一個(gè)hprof文件一樣了。

4.Allaction Tracking

Allocation Tracker(AS)工具比Allocation Tracker(Eclipse)工具強(qiáng)大的地方是更炫酷,更清晰,但是能做的事情都是一樣的。所以我們就分析Android Studio中的。

(1).Allocation Tracker啟動(dòng),生成alloc文件
image22.png
(2).分析alloc文件
image23.png

這邊有兩種顯示的方式:
*Group by Method:用方法來(lái)分類(lèi)我們的內(nèi)存分配
*Group by Allocator:用內(nèi)存分配器來(lái)分類(lèi)我們的內(nèi)存分配
首先以線(xiàn)程對(duì)象分類(lèi),默認(rèn)以分配順序來(lái)排序,當(dāng)然你可以更改,只需在Size上點(diǎn)擊一下就會(huì)倒序,如果以Count排序也是一樣,Size就是內(nèi)存大小,Count就是分配了多少次內(nèi)存,點(diǎn)擊一下線(xiàn)程就會(huì)查看每個(gè)線(xiàn)程里所有分配內(nèi)存的方法

當(dāng)你以Group by Allocator來(lái)查看內(nèi)存分配的情況時(shí),詳細(xì)信息區(qū)域就會(huì)變成如下


image24.png

這種方式顯示的好處,是我們很好的定位我們自己的代碼的分析信息


分類(lèi)旁邊還有跳轉(zhuǎn)到源碼的位置和統(tǒng)計(jì)圖。
輪胎圖

image25.png

輪胎圖是以圓心為起點(diǎn),最外層是其內(nèi)存實(shí)際分配的對(duì)象,每一個(gè)同心圓可能被分割成多個(gè)部分,代表了其不同的子孫,每一個(gè)同心圓代表他的一個(gè)后代,每個(gè)分割的部分代表了某一帶人有多人,你雙擊某個(gè)同心圓中某個(gè)分割的部分,會(huì)變成以你點(diǎn)擊的那一代為圓心再向外展開(kāi)。如果想回到原始狀態(tài),雙擊圓心就可以了。

柱狀圖
柱狀圖以左邊為起始點(diǎn),從左到右的順序是某個(gè)的堆棧信息順序,縱坐標(biāo)上的寬度是以其Count/Size的大小決定的。柱狀圖的內(nèi)容其實(shí)和輪胎圖沒(méi)什么特別的地方


image26.png

5.TraceView

從代碼層面分析性能問(wèn)題,針對(duì)每個(gè)方法來(lái)分析,比如當(dāng)我們發(fā)現(xiàn)我們的應(yīng)用出現(xiàn)卡頓的時(shí)候,我們可以來(lái)分析出現(xiàn)卡頓時(shí)在方法的調(diào)用上有沒(méi)有很耗時(shí)的操作.
主要是下面兩個(gè)問(wèn)題:

  • 調(diào)用次數(shù)不多,但是每一次執(zhí)行都很耗時(shí)
  • 方法耗時(shí)不大,但是調(diào)用次數(shù)太多

簡(jiǎn)單一點(diǎn)來(lái)說(shuō)就是我們能找到頻繁被調(diào)用的方法,也能找到執(zhí)行非常耗時(shí)的方法,前者可能會(huì)造成Cpu頻繁調(diào)用,手機(jī)發(fā)燙的問(wèn)題,后者就是卡頓的問(wèn)題.

(1).打開(kāi)Android device monitor,選中我們的應(yīng)用,點(diǎn)擊start method profiling,開(kāi)始trace
image30.png
(2).操作我們的應(yīng)用,再次點(diǎn)擊上面的按鈕,生成trace文件
image31.png

traceview的面板分上下兩個(gè)部分:
*時(shí)間線(xiàn)面板以每個(gè)線(xiàn)程為一行,右邊是該線(xiàn)程在整個(gè)過(guò)程中方法執(zhí)行的情況
*分析面板是以表格的形式展示所有線(xiàn)程的方法的各項(xiàng)指標(biāo)

時(shí)間線(xiàn)面板
左邊是線(xiàn)程信息,main線(xiàn)程就是Android應(yīng)用的主線(xiàn)程,這個(gè)線(xiàn)程是都會(huì)有的,其他的線(xiàn)程可能因操作不同而發(fā)生改變.每個(gè)線(xiàn)程的右邊對(duì)應(yīng)的是該線(xiàn)程中每個(gè)方法的執(zhí)行信息,左邊為第一個(gè)方法執(zhí)行開(kāi)始,最右邊為最后一個(gè)方法執(zhí)行結(jié)束,其中的每一個(gè)小立柱就代表一次方法的調(diào)用,你可以把鼠標(biāo)放到立柱上,就會(huì)顯示該方法調(diào)用的詳細(xì)信息,你可以隨意滑動(dòng)你的鼠標(biāo),滑倒哪里,左上角就會(huì)顯示該方法調(diào)用的信息。

分析面板
面板列名含義:

    Name    方法的詳細(xì)信息,包括包名和參數(shù)信息
    Incl Cpu Time   Cpu執(zhí)行該方法該方法及其子方法所花費(fèi)的時(shí)間
    Incl Cpu Time % Cpu執(zhí)行該方法該方法及其子方法所花費(fèi)占Cpu總執(zhí)行時(shí)間的百分比
    Excl Cpu Time   Cpu執(zhí)行該方法所話(huà)費(fèi)的時(shí)間
    Excl Cpu Time % Cpu執(zhí)行該方法所話(huà)費(fèi)的時(shí)間占Cpu總時(shí)間的百分比
    Incl Real Time  該方法及其子方法執(zhí)行所話(huà)費(fèi)的實(shí)際時(shí)間,從執(zhí)行該方法到結(jié)束一共花了多少時(shí)間
    Incl Real Time %    上述時(shí)間占總的運(yùn)行時(shí)間的百分比
    Excl Real Time %    該方法自身的實(shí)際允許時(shí)間
    Excl Real Time  上述時(shí)間占總的允許時(shí)間的百分比
    Calls+Recur 調(diào)用次數(shù)+遞歸次數(shù),只在方法中顯示,在子展開(kāi)后的父類(lèi)和子類(lèi)方法這一欄被下面的數(shù)據(jù)代替
    Calls/Total 調(diào)用次數(shù)和總次數(shù)的占比
    Cpu Time/Call   Cpu執(zhí)行時(shí)間和調(diào)用次數(shù)的百分比,代表該函數(shù)消耗cpu的平均時(shí)間
    Real Time/Call  實(shí)際時(shí)間于調(diào)用次數(shù)的百分比,該表該函數(shù)平均執(zhí)行時(shí)間

6.LeakCanary

quare公司開(kāi)發(fā)的可以直接在手機(jī)端查看內(nèi)存泄露的工具
實(shí)現(xiàn)原理:本質(zhì)上還是用命令控制生成hprof文件分析檢查內(nèi)存泄露。
GitHub:https://github.com/square/leakcanary

使用:

(1).添加如下依賴(lài)
    debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
    releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
(2).添加Application子類(lèi)

首先創(chuàng)建一個(gè)ExampleApplication,該類(lèi)繼承于Application,在該類(lèi)的onCreate方法中添加如下代碼開(kāi)啟LeakCanary監(jiān)控:

    LeakCanary.install(this);

具體的就不在說(shuō)了,網(wǎng)上有很多,使用起來(lái)先對(duì)比較簡(jiǎn)單。

7.Lint

android stidio 自帶的工具,功能很強(qiáng)大。
主要功能:

  • 檢測(cè)資源文件是否有沒(méi)有用到的資源。
  • 檢測(cè)常見(jiàn)內(nèi)存泄露
  • 安全問(wèn)題SDK版本安全問(wèn)題
  • 是否有沒(méi)有使用的代碼
  • 代碼的規(guī)范
  • 自動(dòng)生成的羅列出來(lái)
  • 提示去除沒(méi)用的導(dǎo)包
  • 提示可能的bug
image27.png

點(diǎn)擊inpsect code,工具就會(huì)自動(dòng)分析你的項(xiàng)目代碼。


image28.png

(1). correctness 有錯(cuò)誤的代碼
(2). performance 性能方面
(3). security 安全方面,常見(jiàn)的是備份
(4). usability 應(yīng)該使用的方式
(5).class structure 類(lèi)結(jié)構(gòu)問(wèn)題
(6). control flow issues 控制流程問(wèn)題
(7). declaration redundancy 聲明冗余
(8). imports 提示去除沒(méi)用的導(dǎo)包
(9). probable bugs 可能的bug
(10). spelling 代碼的規(guī)范,駝峰命名法等

我們主要看下內(nèi)存泄漏有沒(méi)有提示:


image29.png

我們看到這里直接提示我們可能出現(xiàn)的內(nèi)存泄漏,很強(qiáng)大呀!

補(bǔ)充:在打包發(fā)布時(shí),可以用Lint工具來(lái)去除多余的沒(méi)有使用的資源和類(lèi),來(lái)減小apk的體積。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 每個(gè)人都有自己的秘密 秘密使人變的神秘 秘密使人變的更加謹(jǐn)慎 秘密使人變的更加努力 秘密使人變的更加強(qiáng)大 秘密使生...
    淡淡27閱讀 245評(píng)論 0 0
  • 1986年青島作為五個(gè)城市之一,列為單列經(jīng)濟(jì)城市。什么叫單列呢?就是這類(lèi)城市由中央來(lái)管轄?zhēng)煾?,是副省?jí)的單位。 這...
    RGLR閱讀 338評(píng)論 0 0
  • DVWA-1.9系列一共分為10個(gè)功能模塊: Brute Force(暴力破解) Command Injectio...
    網(wǎng)絡(luò)安全自修室閱讀 1,579評(píng)論 0 0
  • 如果你從這篇文章中看到了你的影子,別太在意,我不是在寫(xiě)你,但又有可能在寫(xiě)你。 天暗了下來(lái),是回家的時(shí)間了,我特意沒(méi)...
    解憂(yōu)少年閱讀 589評(píng)論 11 7
  • 從前,一直聽(tīng)身邊的同事在不同的場(chǎng)景中說(shuō),要學(xué)會(huì)換位思考。 給他人留有印象之時(shí),也不是談起,要學(xué)會(huì)換位思考。 前段時(shí)...
    夏日嬤嬤茶1008閱讀 1,517評(píng)論 0 0

友情鏈接更多精彩內(nèi)容