前言: 最近在系统性的温习了一遍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中:
会发一些大白话实用的文章。也一直在寻找最有利的面试技巧。有想法的同窗能够一块儿