标签:灰色 strip 方法 jpg 分割 net 顺序查找 技术 停止
上篇说了一些性能优化的理论部分,主要是回顾一下,有了理论,小平同志又讲了,实践是检验真理的唯一标准,对于内存泄露的问题,现在通过Android Studio自带工具Memory Monitor 检测出来。性能优化的重要性不需要在强调,但是要强调一下,我并不是一个老司机,嘿嘿!没用过这个工具的,请睁大眼睛。如果你用过,那么就不用在看这篇博客了。
先看一段会发生内存泄露的代码
public class UserManger {
private static UserManger instance;
private Context context;
private UserManger(Context context) {
this.context = context;
}
public static UserManger getInstance(Context context) {
if (instance == null) {
instance = new UserManger(context);
}
return instance;
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
UserManger userManger = UserManger.getInstance(this);
}
}
代码很简单,就是一个单利模式泄露的场景,我们现在的关心的不是代码本身,而是如何将代码里面的内存泄露给找出来。但是对于上面的代码发生内存泄露的原因还是有必要提一下。
上篇博客说了,内存泄漏产生的原因是:当一个对象已经不需要再使用了,本该被回收时,而有另外一个正在使用的对象持有它的引用从而就导致,对象不能被回收。这种导致了本该被回收的对象不能被回收而停留在堆内存中,就产生了内存泄漏。
在上面的代码中,发生泄露的不是UserManger,而是MainActivity,UserManger中有一个静态成员instance,其生命周期和应用程序的生命周期一致,当退出应用时,才能被销毁,但是当GC准备回收MainActivity时,结果呢MainActivity的对象(this)在被UserManger所引用,UserManger本身又不能被干掉,所以就发生了内存泄露。
Memory Monitor是Android Monitors中的一种,Monitors主要包括四种,Memory
Monitor ,CPU Monitor ,NetWork Monitor, GPU Monitor ,今天介绍的是Memory
Monitor ,其他的Monitor,在后面也准备讲。
回到我们的程序,多点击几次GC,看一下这个应用的内存使用情况。
可以看到现在已经分配的内存有19.68M,我把手机旋转一下,在看。
可以看到现在的内存使用量是21.09M,还是一样的界面,却多了1.41M!!!这很关键。
接下来,我们找一下,哪里发生了泄露。点击Dump Java Heap,生成快照文件tool.test.memory.memoryleak_2016.11.13_21.38.hprof,Android Studio 自动弹出HPROF Viewer来分析它。
现在介绍一下HPROF Viewer的用法
我通常点击App heap下面的Classs Name把Heap中所有类按照字母顺序排序,然后按照字母顺序查找。
列名 | 解释 |
---|---|
Class Name | 类名,Heap中的所有Class |
Total Count | 内存中该类这个对象总共的数量,有的在栈中,有的在堆中 |
Heap Count | 堆内存中这个类 对象的个数 |
Sizeof | 每个该实例占用的内存大小 |
Shallow Size | 所有该类的实例占用的内存大小 |
Retained Size | 所有该类对象被释放掉,会释放多少内存 |
列名 | 解释 |
---|---|
Instance | 该类的实例 |
Depth | 深度, 从任一GC Root点到该实例的最短跳数 |
Dominating Size | 该实例可支配的内存大小 |
B板块右上角有个"的按钮, 点击会进入HPROF Analyzer的hprof的分析界面:
"
在这个界面中可以直接把内存泄露可能的类找出来。
多方面的证据表明MainActivity发生了内存泄露
解决方案
public class UserManger {
private static UserManger instance;
private Context context;
private UserManger(Context context) {
this.context = context;
}
public static UserManger getInstance(Context context) {
if (instance == null) {
if(context!=null){
instance = new UserManger(context.getApplicationContext());
}
}
return instance;
}
}
不要用Activity的Context,因为Activity随时可能被回收,我们用Application的Context,Application的Context的生命周期是整个应用,不回收也没有关系。
Memory Monitor获得内存的动态视图,Heap Viewer显示堆内存中存储了什么,可惜Heap Viewer不能显示你的数据具体分配在代码的何处,如果还不过瘾,想知道具体是哪些代码使用了内存,还有一个功能是Allocation Tracker,用来内存分配追踪。在内存图中点击途中标红的部分,启动追踪,再次点击就是停止追踪,随后自动生成一个alloc结尾的文件,这个文件就记录了这次追踪到的所有数据,然后会在右上角打开一个数据面板
Allocation Tracker启动追踪
,
Allocation Tracker查看方式
有两种查看方式,默认是Group by Method方式
从上图可以看出,首先以线程对象分类,Size是内存大小,Count是分配了多少次内存,点击一下线程就会查看每个线程里所有分配内存的方法
Group by Method方式
OK,-Memory Monitor
Group by Allocator方式
右键可以直接跳到源码
- 扇形统计图
点击统计图按钮,会生成上图,扇形统计图是以圆心为起点,最外层是其内存实际分配的对象,每一个同心圆可能被分割成多个部分,代表了其不同的子孙,每一个同心圆代表他的一个后代,每个分割的部分代表了某一带人有多人,你双击某个同心圆中某个分割的部分,会变成以你点击的那一代为圆心再向外展开。
Memory Monitor工具为监控工具,是一种发现型或者说监控性质的工具,比如医生的四大技能[望闻问切],[望]是第一步。这里的Memory Monitor就是一种[望]的工具,目前我主要用它来看下面几个内存问题:
1.发现内存抖动的场景
2.发现大内存对象分配的场景
3.发现内存不断增长的场景
4.确定卡顿问题是否因为执行了GC操作
上面的第一段标记显示内存突然增加了7M,我们也能看的很清楚,所以这个点我们要去定位了一下问题在哪里,是Bitmap还是什么原因造成的,第二段标记是内存抖动,很明显在很短的时间了发生了多次的内存分配和释放。而且在发生内存抖动的时候,也能感觉到App的卡顿,可以看出来是由于执行了GC操作造成的。
内存的不断增加通过Memory monitor很容易看出来,蓝色的曲线是一路高歌猛进的,一看便知。
Android性能优化第(二)篇---Memory Monitor检测内存泄露
标签:灰色 strip 方法 jpg 分割 net 顺序查找 技术 停止
原文地址:http://www.cnblogs.com/ldq2016/p/6628311.html