前言: 最近在系統性的溫習了一遍android性能優化。寫博客是學習也是記錄,但願在記錄的同時也能幫助其餘同窗。最近我以爲我想出一個不懂系列。「不懂揍我」,「不懂砍我」,「不懂捶我」php
在咱們開發項目中,若是稍不注意,每每會出現內存抖動的狀況。而有些內存抖動也可能形成咱們的程序卡頓,甚至泄漏。接下來使用Android Studio自帶的Profiler分析內存抖動。java
首先在MainActivity建立一段內存抖動的代碼:android
private Handler mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
//創造內存抖動
for (int i = 0; i < 100; i++) {
String arg[] = new String[100000];
}
mHandler.sendEmptyMessageDelayed(0, 30);
}
};
複製代碼
運行以後出現以下圖,面試
點擊按鈕,觸發內存抖動的代碼,來看看咱們的內存狀況,能夠看到呈鋸齒狀數據庫
點擊上圖紅色框內record,而後點擊stop分析一段咱們的鋸齒狀,如圖:性能優化
Allocations: 表示當前分配的數量
Shallow Size: 表示當前內存佔用狀況dom
能夠看到咱們的String[]佔用最多,左鍵點擊String[]後,右側會出現全部的String[],而後左鍵點擊任意一個,會出現Allocation Call Stack:內存分配的堆棧信息:eclipse
能夠很明顯看到在咱們代碼裏,是由於handleMessage:21, MainActivity$1 (com.leo.memoryanalyzertest),形成的內存抖動。右鍵這條,點擊Jump to Source.能夠跳轉到咱們的問題代碼。這就是咱們Profiler分析內存抖動的狀況。ide
首先咱們推測下,traceView是分析卡頓利器,固然在這裏能測出。但要知道它是偏向耗時狀況的。上篇說過,這裏就不說明了。一樣點擊CPU,而後record,stop記錄一段。如圖來到咱們的Top Down:性能
能夠看到耗時時間在MessageQueue裏,這也正和咱們的內存抖動代碼相關聯,每間隔30ms發送一次,在handleMessage()裏,也指明瞭代碼在com.leo.memoryanalyzertest.MainActivity裏。能夠發現這種方式去分析,並不明顯。
注意:咱們都知道內存抖動,咱們要尋找的話,也是找循環或者頻繁調用的地方。因此這麼看咱們用CPU Profiler的方式也能大概確認問題代碼的位置。
一樣咱們先建立一段內存泄漏的代碼,先定義個接口
public interface CallBack {
void leoFun();
}
複製代碼
而後建立個靜態list,添加CallBack實例
public class CallBackManager {
public static ArrayList<CallBack> sCallBacks = new ArrayList<>();
public static void addCallBack(CallBack callBack) {
sCallBacks.add(callBack);
}
public static void removeCallBack(Callback callback) {
sCallBacks.remove(callback);
}
}
複製代碼
再建立個BitmapActivity實現CallBack接口,設置一個大圖main_bg,同時把實例假如到靜態sCallBacks中,這樣每次打開BitmapActivity而後退出,都會形成BitmapActivity不能被回收。
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bitmap);
ImageView imageView = findViewById(R.id.image);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.main_bg);
imageView.setImageBitmap(bitmap);
CallBackManager.addCallBack(this);
}
複製代碼
這樣咱們不停打開這個頁面而後關掉看內存狀況,如圖,能夠看到內存直接上升:
紅色框1:功能是主動發起一次gc。目的是回收一些可回收的,虛引用等。避免內存分析干擾
紅色框2: 堆轉儲,將內存分配狀況轉換成hprof文件。(注意這裏是studio的hprof文件,若是須要用Memory Analyzer分析,還要轉換成標準的hprof文件)
點擊右鍵Export,將文件存儲在文件夾裏。
轉換成mat能識別的hprof文件,只要cmd命令行來到咱們的studio自帶的hprof-conv.exe文件下,輸入命令,便可轉換
hprof-conv 源文件路徑 輸出文件路徑,這樣就生成了咱們的my.hprof
生成了hprof文件後,而後就是使用Memory Analyzer。 官網下載地址:www.eclipse.org/mat/downloa…,由於捐贈什麼的,不建議。我這找到了一個比較靠譜的版本,csdn下載
下載好後啓動咱們的MemoryAnalyzer.exe。File --> Open Heap Dump打開咱們的my.hprof文件如圖:
先簡單介紹下Memory Analyzer的信息。
咱們能夠利用直方圖,裏的Regex搜索咱們最開始的內存泄漏案例。搜索BitmapActivity如圖,能夠看到咱們的BitmapActivity有3個實例:
咱們能夠右鍵點擊com.leo.me,oryanalyzertest.BitmapActivity --> List objects --> with incoming reference (誰引用了我),如圖能夠看到有3個地方引用了BitmapActivity:
此時咱們右鍵一個實例點擊 Path To GC Roots --> with all refrence,如圖,找到文件下帶小太陽的文件,可能觸發內存溢出的地方。這裏是說咱們的sCallBacks引用了,也證明了在咱們內存泄漏代碼裏的CallBackManager裏的靜態集合sCallBacks添加了它。
能夠看到咱們這裏的大頭是bitmap。
一樣咱們能夠經過右鍵一個實例Path To GC Roots --> with all refrence如圖,也能看到是咱們的sCallBacks引用了:
寫入命令後,點擊紅色感嘆號運行,如圖
展現咱們內存中佔有比較大的內存,能夠看到這裏都是被3個大bitmap佔據着。直觀利於分析
這裏我啓動了3次BitmapActivity,它也給了我3個分析。點擊details。看詳情,也直接把問題定在了sCallBacks中:
會發一些大白話實用的文章。也一直在尋找最有利的面試技巧。有想法的同窗能夠一塊兒