Android 性能之內存優化

和你一起終身學習,這裏是程序員 Android

經典好文推薦,通過閱讀本文,您將收穫以下知識點:

一、Heap Snapshot
二、Heap Viewer
三、MAT
四、Allaction Tracking
五、TraceView
六、LeakCanary
七、Lint

一、Heap Snapshot

Heap Snapshot 是 android Studio 中 Android Monitor中的一個分析Java堆內存信息的工具,這邊我們就用上章中的單例導致內存泄漏的例子來分析:

(1).Heap Dump啓動

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

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

android studio會自動打開hprof文件,我們這時候就可以來重點分析我們需要檢查的類是否有內存泄漏(必須要確定分析具體的類,比如我們分析MainActivity是否有內存泄漏,可以反覆的改變屏幕的方向,然後dump出堆信息)

我們看到ClassName中可能數據太多,我們怎麼能夠定位到我們要分析的類呢,可以選擇第二個紅色框中的選擇項來快的定位。

我們選擇通過包來展示,這樣可以通過包名來快速定位。


下面我們來分析下MainActivity是否有內存泄漏。

我們看到這裏MainActivity有兩個實例且都有深度,也就是說都被引用,根據Acitivity的生命週期原理,屏幕的旋轉會回收之前的Activity,然後創建一個新的Activity,另一個一個被回收或者等待被回收,所以MainActivity肯定存在內存泄漏的問題。這個需要結合下面的引用樹來看,但是這個太麻煩還不要用對,下面我們將介紹更好的工具來分析,這邊只要知道我們分析的類是否發生內存泄漏就行了。

(3)Snapshot中表中字段含意:

Class Name 板塊
Total Count 內存中該類的對象個數
Heap Count 堆內存中該類的對象個數
Sizeof 物理大小
Shallow size 該對象本身佔有內存大小
Retained Size 釋放該對象後,節省的內存大小
Instance 板塊

depth           深度
Shallow Size    對象本身內存大小
Dominating Size 管轄的內存大小

二、Heap Viewer

Heap Viewer 是 Android Device Monitor 中的實時查看App分配的內存大小和空閒內存大小和發現內存泄漏的工具。
使用條件:1.必須5.0以及以上的系統,2.開發者選項可用

使用步驟:

1.打開Android Device Monitor
2.點擊DDMS
3.選中heap選項卡
4.選中我們的項目
5.點擊update heap
6.點擊Cause GC


下面解釋下Heap面板中表示的意思:


A

Heap Size   堆棧分配給App的內存大小
Allocated   已分配使用的內存大小
Free    空閒的內存大小
%Used   Allocated/Heap Size,使用率
Objects 對象數量

B 中 Type 類型

free    空閒的對象
data object 數據對象,類類型對象,最主要的觀察對象
class object    類類型的引用對象
1-byte array(byte[],boolean[])  一個字節的數組對象
2-byte array(short[],char[])    兩個字節的數組對象
4-byte array(long[],double[])   4個字節的數組對象
non-Java object 非Java對象

B 中 表中列的表示意思

Count   數量
Total Size  總共佔用的內存大小
Smallest    將對象佔用內存的大小從小往大排,排在第一個的對象佔用內存大小
Largest 將對象佔用內存的大小從小往大排,排在最後一個的對象佔用的內存大小
Median  將對象佔用內存的大小從小往大排,拍在中間的對象佔用的內存大小
Average 平均值

當我們點擊某一行時,可以看到 C 的柱狀圖 ,表示 橫座標是對象的內存大小,這些值隨着不同對象是不同的,縱座標是在某個內存大小上的對象的數量

下面我們來發現有內存泄漏的單例例子:

(1).旋轉屏幕前,我們看到已經分配的內存爲814.617kb(手動GC):

(2).旋轉屏幕後,我們看到已經分配的內存爲956.891kb(手動GC):

我們對比前後的兩次發現有內存不能被回收,也就是說旋轉屏幕導致內存泄漏了。這個工具沒法具體定位到內存泄漏的位置。

補充:Heap Viewer不光可以用來檢測是否有內存泄漏,對於內存抖動,我們也可以用該工具檢測,因爲內存抖動的時候,會頻繁發生GC,這個時候我們只需要開啓Heap Viewer,觀察數據的變化,如果發生內存抖動,會觀察到數據在段時間內頻繁更新

三、 MAT

全稱爲Memory Analyzer Tool,一款詳細分析Java堆內存的工具,該工具非常強大,爲了使用該工具,我們需要hprof文件。但是該文件不能直接被MAT使用,需要進行一步轉化,可以使用hprof-conv命令來轉化,但是Android Studio可以直接轉化.

下面我們就來那Heap Snapshot 中的hprof來分析:

(1).轉換hprof文件

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

工具會自動生成一個可疑的內存泄漏,其實這裏對我們用處不大,我們主要分析overView選項卡。

我們看到這裏給出了一些基本的數據我大對象的圖,我們主要分析下面的Actions中的三個工具:
Histogram
主要是列出每個類中對象,點擊看下:

我們看到這邊的對象有點多,我們選擇按照包來顯示,或者通過regex來篩選。


找到我們要分析的類,選擇ListObject中的with incoming references,來顯示引用MainActivity的類。


我們看到這邊有兩個地方引用了MainActivity,然後現在圖中的選項,排除所有的soft,weak,phantom引用,看看當前的被什麼引用。我們來看下兩個結果:


我們看到一個被CommonUtil引用,導致內存泄漏,一個被InputMethodManger引用,導致內存泄漏,第二個是系統輸入法的bug,而第一個是我們自己寫的,如果列表中顯示很多我們只能一一分析。

上面是分析一個hprof來看,可能有時也看不出來,那麼我們可以通過兩個hprof來對比分析。

對比分析
(1).將兩個hprof文件添加到工具中
(2).將兩個hprof文件添加到對比列表中

(3).對比分析

我們看到經過旋轉操作,MainActivity有兩個,所以這邊肯定發生了內存泄漏,那到底是什麼引起內存泄漏的呢?下面的分析步驟就和上面單獨分析一個hprof文件一樣了。

四、Allaction Tracking

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

(1).Allocation Tracker啓動,生成alloc文件

(2).分析alloc文件

這邊有兩種顯示的方式:
*Group by Method:用方法來分類我們的內存分配
*Group by Allocator:用內存分配器來分類我們的內存分配
首先以線程對象分類,默認以分配順序來排序,當然你可以更改,只需在Size上點擊一下就會倒序,如果以Count排序也是一樣,Size就是內存大小,Count就是分配了多少次內存,點擊一下線程就會查看每個線程裏所有分配內存的方法

當你以Group by Allocator來查看內存分配的情況時,詳細信息區域就會變成如下

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

分類旁邊還有跳轉到源碼的位置和統計圖。
輪胎圖


輪胎圖是以圓心爲起點,最外層是其內存實際分配的對象,每一個同心圓可能被分割成多個部分,代表了其不同的子孫,每一個同心圓代表他的一個後代,每個分割的部分代表了某一帶人有多人,你雙擊某個同心圓中某個分割的部分,會變成以你點擊的那一代爲圓心再向外展開。如果想回到原始狀態,雙擊圓心就可以了。

柱狀圖
柱狀圖以左邊爲起始點,從左到右的順序是某個的堆棧信息順序,縱座標上的寬度是以其Count/Size的大小決定的。柱狀圖的內容其實和輪胎圖沒什麼特別的地方

五、TraceView

從代碼層面分析性能問題,針對每個方法來分析,比如當我們發現我們的應用出現卡頓的時候,我們可以來分析出現卡頓時在方法的調用上有沒有很耗時的操作.
主要是下面兩個問題:

調用次數不多,但是每一次執行都很耗時
方法耗時不大,但是調用次數太多
簡單一點來說就是我們能找到頻繁被調用的方法,也能找到執行非常耗時的方法,前者可能會造成Cpu頻繁調用,手機發燙的問題,後者就是卡頓的問題.

(1).打開Android device monitor,選中我們的應用,點擊start method profiling,開始trace

(2).操作我們的應用,再次點擊上面的按鈕,生成trace文件

traceview的面板分上下兩個部分:

  • 時間線面板以每個線程爲一行,右邊是該線程在整個過程中方法執行的情況
  • 分析面板是以表格的形式展示所有線程的方法的各項指標

時間線面板
左邊是線程信息,main線程就是Android應用的主線程,這個線程是都會有的,其他的線程可能因操作不同而發生改變.每個線程的右邊對應的是該線程中每個方法的執行信息,左邊爲第一個方法執行開始,最右邊爲最後一個方法執行結束,其中的每一個小立柱就代表一次方法的調用,你可以把鼠標放到立柱上,就會顯示該方法調用的詳細信息,你可以隨意滑動你的鼠標,滑倒哪裏,左上角就會顯示該方法調用的信息。

分析面板
面板列名含義:

Name    方法的詳細信息,包括包名和參數信息
Incl Cpu Time   Cpu執行該方法該方法及其子方法所花費的時間
Incl Cpu Time % Cpu執行該方法該方法及其子方法所花費佔Cpu總執行時間的百分比
Excl Cpu Time   Cpu執行該方法所話費的時間
Excl Cpu Time % Cpu執行該方法所話費的時間佔Cpu總時間的百分比
Incl Real Time  該方法及其子方法執行所話費的實際時間,從執行該方法到結束一共花了多少時間
Incl Real Time %    上述時間佔總的運行時間的百分比
Excl Real Time %    該方法自身的實際允許時間
Excl Real Time  上述時間佔總的允許時間的百分比
Calls+Recur 調用次數+遞歸次數,只在方法中顯示,在子展開後的父類和子類方法這一欄被下面的數據代替
Calls/Total 調用次數和總次數的佔比
Cpu Time/Call   Cpu執行時間和調用次數的百分比,代表該函數消耗cpu的平均時間
Real Time/Call  實際時間於調用次數的百分比,該表該函數平均執行時間

六、LeakCanary

quare公司開發的可以直接在手機端查看內存泄露的工具
實現原理:本質上還是用命令控制生成hprof文件分析檢查內存泄露。
GitHub:https://github.com/square/leakcanary

使用:

(1).添加如下依賴

debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'

(2).添加Application子類

首先創建一個ExampleApplication,該類繼承於Application,在該類的onCreate方法中添加如下代碼開啓LeakCanary監控:

LeakCanary.install(this);

具體的就不在說了,網上有很多,使用起來先對比較簡單。

七、Lint

android stidio 自帶的工具,功能很強大。

主要功能:

檢測資源文件是否有沒有用到的資源。
檢測常見內存泄露
安全問題SDK版本安全問題
是否有沒有使用的代碼
代碼的規範
自動生成的羅列出來
提示去除沒用的導包
提示可能的bug

點擊inpsect code,工具就會自動分析你的項目代碼。

(1). correctness 有錯誤的代碼
(2). performance 性能方面
(3). security 安全方面,常見的是備份
(4). usability 應該使用的方式
(5).class structure 類結構問題
(6). control flow issues 控制流程問題
(7). declaration redundancy 聲明冗餘
(8). imports 提示去除沒用的導包
(9). probable bugs 可能的bug
(10). spelling 代碼的規範,駝峯命名法等

我們主要看下內存泄漏有沒有提示:

我們看到這裏直接提示我們可能出現的內存泄漏,很強大呀!

補充:在打包發佈時,可以用Lint工具來去除多餘的沒有使用的資源和類,來減小apk的體積。

參考鏈接:https://www.jianshu.com/p/b6684e5880d9

至此,本篇已結束。轉載網絡的文章,小編覺得很優秀,歡迎點擊閱讀原文,支持原創作者,如有侵權,懇請聯繫小編刪除,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章