用新版的AS 的profiler 查看内存泄漏
记录一下使用Android Studio 的profiler 查看内存泄漏的过程。新版的AS 的profiler 功`能强大。我们可以很方便的查看到一个界面里的内存泄漏。
首先我们来看看不发生内存泄漏时候的情况:
public class MemoryLeakActivity extends AppCompatActivity {
private ValueAnimator count20sToStop;
// 这里有在onDestory里处理,这样做肯定会避免掉当前情况下handler的内存泄露
@Override
protected void onDestroy() {
super.onDestroy();
mHandle.removeMessages(FLAG);
}
private static int FLAG = 999;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_memory_leak);
Button btn = findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
mHandle.sendEmptyMessageDelayed(FLAG, 1000);
}
private Handler mHandle = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
mHandle.sendEmptyMessageDelayed(FLAG, 1000);
}
};
}
确实没有泄露的地方。
然后我们制造一个内存泄漏的Activity。 把onDestory去掉。肯定会发生内存泄漏的。
public class MemoryLeakActivity extends AppCompatActivity {
private static int FLAG = 999;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_memory_leak);
Button btn = findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
mHandle.sendEmptyMessageDelayed(FLAG, 1000);
}
private Handler mHandle = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
mHandle.sendEmptyMessageDelayed(FLAG, 1000);
}
};
}
然后点开AS 的profiler
然后我们可以查看到我们应用运行时候的cpu 内存等数据的情况。这里我们只要关注内存即可。
接下来我们从启动页面跳转到有内存泄漏的那个Activity。
这里可以看到我们从LunchActivity 跳转到了MemoryLeakActivity。
接下来我们点击button finish()掉 MemoryLeakActivity。回到我们原来的起动页面。这时候点垃圾桶,触发几次gc。
这些小垃圾桶就代表我们触发的gc.
然后选取record 来记录我们产生的内存泄漏。
新版的AS的Record 点一下就可以为我们自动记录一段内存快照。然后直接弹出我们的内存数据。不用像以前一样你需要拉一段距离。
这里很清晰的给我们指出有2出内存泄漏。
点一下这个 2 Leaks 就会直接显示出内存泄漏的类的包名位置(非常人性化)。
这里我们看到内存泄漏的位置一个是我们自己的Activity里Handler 造成的内侧泄漏。一处是系统里ReportFragment发生的内侧泄漏。 这个估计也跟Handler 有关。
然后我们点到相关的类还可以进一步查看内存泄漏的类的引用关系
使用MemoryAnalyzer
我们也可以导出内存快照。使用mat来进行内存分析。
首先使用 hprof-conv.exe 来转换一下我们导出的内存快照。记得把platform-tools 配置到环境变量里你才能找到hprof-conv 这个命令。
hprof-conv -z 1.hprof 1-mat.hprof
生成一个新文件
打开Mat 导入 1-mat.hprof : file->Open Dump Heap 。 点击finish
这里 Shallow Size是对象本身占据的内存的大小,不包含其引用的对象。对于常规对象(非数组)的Shallow Size由其成员变量的数量和类型来定,而数组的ShallowSize由数组类型和数组长度来决定,它为数组元素大小的总和。
Retained Size=当前对象大小+当前对象可直接或间接引用到的对象的大小总和。(间接引用的含义:A->B->C,C就是间接引用) ,并且排除被GC Roots直接或者间接引用的对象。
我们进一步操作排除软引用,弱引用,虚引用看看剩下哪些东西。
然后我们就可以看到排除完软引用,弱引用,虚引用后内存里剩下的对象。根据剩余的对象来分析内存泄漏。
整体来看Mat 不如新版AS的profiler好用。新版AS的profiler基本上算是傻瓜式的使用了。只要目前看在安卓开发中只要会用新版AS 的profiler 即可。