概述
本文介紹android分析内存的几种方法。大概有四个方法可以分析内存:Memory,ART的GC Log,DDMS的Heap分析,内存分析工具进行分析(本文主要讲下MAT的分析方法)。
1.Monitors下的可视图Memory分析内存
android studio提供了Monitors可以观察Memory,CPU,Network和GPU的使用情况。
Memory实时显示了内存的的占用情况。蓝色部分显示占用的内存,灰色部分表示空闲的内存。
Memory大体可以分析出下列情况
(1)可以观察到哪个地方内存占用暴增,也可以观察到内存占用的减少
(2)如果内存占用该下降时,但没减少,可以分析出该模块出现内存泄露
(3)如图红色框显示则出现了内存抖动。当一段时间大量的创建和回收对象就会造成内存抖动,因为创建对象会占用内存,回收对象时释放内存。因为当发生GC时,会暂停其它线程,如果频繁GC会造成程序的卡顿。
如下代码。通过定时器不断的Copy Bitmap对象,因为创建Bitmap时会暂用大量内存,而又马上释放,则出现如图内存抖动的现象。
public class MainActivity extends Activity {
private Button button;
private Timer timer;
private TimerTask timerTask;
private Bitmap bitmap;
private boolean flag;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 1:
Bitmap bitmap1 = bitmap.copy(Bitmap.Config.ARGB_8888,true);
bitmap1.recycle();
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(!flag){
start();
}else {
stop();
}
}
});
}
private void start(){
bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.brother);
flag = true;
timer = new Timer();
timerTask = new TimerTask() {
@Override
public void run() {
handler.sendEmptyMessage(1);
}
};
timer.schedule(timerTask,0,100);
}
private void stop(){
flag = false;
if(timer != null ){
timer.cancel();
}
}
}
2.GC之后都会在Logcat输出一段信息
在ART模式下输出的Logcat信息格式如下
I/art: <GC_Reason> <GC_Name> <Objects_freed>(<Size_freed>) AllocSpace Objects, <Large_objects_freed>(<Large_object_size_freed>) <Heap_stats> LOS objects, <Pause_time(s)>
手动进行了GC,如下是实例输出
I/art: Explicit concurrent mark sweep GC freed 52170(2MB) AllocSpace objects, 33(1608KB) LOS objects, 40% free, 16MB/27MB, paused 800us total 85.768ms
因为是手动的GC,所以例子输出的GC Reason为Explicit
如下是各个字段的意思和情况
GC Reason
什么触发了GC,以及属于哪种类型的垃圾回收,一般出现的值包括:
Concurrent
并发GC,不会挂起app线程,这种GC在后台线程中运行,不会阻止内存分配
Alloc
GC被初始化,app在heap已满的时候请求分配内存,此时,GC会在当前线程(请求分配内存的线程)执行
Explicit
GC被app显式请求,例如,通过调用 System.gc() 或者 runtime.gc() 。和Dalvik一样,ART建议相信GC,尽可能地避免请求显式GC。不建议使用显式GC,因为会阻塞当前线程,并引起不必要的CPU周期。如果GC导致其它线程被抢占的话,显式GC还会引发jank
NativeAlloc
来自native分配的native memory压力引起的GC,比如Bitmap或者RenderScript对象
CollectorTransition
heap变迁引起的GC,运行时动态切换GC造成的,垃圾回收器变迁过程包括从free-list backed space复制所有对象到bump pointer space(反之亦然)。当前垃圾回收器过渡只会在低RAM设备的app改变运行状态时发生,比如从可察觉的停顿态到非可察觉的停顿态(反之亦然)
HomogeneousSpaceCompact
Homogeneous space compaction是free-list space与free-list space的合并,经常在app变成不可察觉的停顿态时发生,这样做的主要原因是减少RAM占用并整理heap碎片
GC Name
ART有几种不同的GC
Concurrent mark sweep (CMS)
全堆垃圾收集器,负责收集释放除image外的所有空间
Concurrent partial mark sweep
差不多是全堆垃圾收集器,负责收集除image和zygote外的所有空间
Concurrent sticky mark sweep
分代垃圾收集器,只负责释放从上次GC到现在分配的对象,该GC比全堆和部分标记清除(mark sweep)执行得更频繁,因为它更快而且停顿更短
Marksweep + semispace
非并发的,复制堆过渡和homogeneous space compaction(用来整理heap碎片)使用的GC
Objects freed
本次GC从非大对象空间(non large object space)回收的对象数目
Size freed
本次GC从非大对象空间回收的字节数
Large objects freed
本次GC从大对象空间里回收的对象数目
Large object size freed
本次GC从大对象空间里回收的字节数
Heap stats
可用空间所占的百分比和[已使用内存大小]/[heap总大小]
Pause times
一般情况下,GC运行时,停顿次数和被修改的对象引用数成比例。目前,ART CMS GC只会在GC结束的时停顿一次,GC过渡会有一个长停顿,是GC时耗的主要因素
3.分析Heap的大致情况
打开android device monitor。
Heap信息字段的意义
Heap Size:当前分配的内存;Allocated:已占用的内存;Free:空闲的内存;%Used:已使用内存的占比;Objects:对象数
比如当要分析一个界面是否有内存泄漏。可以在进入界面前手动GC,查看当前的Heap情况。再进入界面,然后退出,手动GC之后查看操作之后的Heap情况,可以分析出该界面是否有内存泄漏。
以上三种方法只能大概分析内存的使用情况,要找出内存泄漏的原因,还要借助第三方工具,本文讲解下MAT的使用。
4.MAT使用方法
先导出hprof文件,通过android studio导出来的hprof,MAT是打不开,要先进行转换。
在androidSdkplatform-tools文件夹,命令行输入 hprof-conv old.hprof new.hprof转换得到新的hprof
打开转换后的hprof文件
MAT分析常用有两种:Histogram和Dominator Tree
(1)先看下Dominator Tree的分析图
Dominator Tree把对象按占用的内存的大小从大到下排列,并可以查看对象之间的引用关系。
Shallow Heap显示对象本身占用的内存,Retained Heap显示对象及其之间引用和间接引用占用的内存。
在对象每一行的左边有的有红色点的标记有的没有,有红色点表示该对象可以被GCRoots访问到。那被红色点标记的就代表这个对象造成了内存泄漏?可以看到第一行的对象右边有System class标识,这代表该对象是由系统创建并管理的,而不是我们自己创建的对象。
自然没被红色点标识的就是GCRoots不能访问到,那么就代表该对象没有造成内存泄漏吗?也有可能该对象持有了别的对象引用,造成了被引用对象的引起的内存泄漏。
上图中在6至10行有多个BitmapState对象,如果怀疑该对象引起了内存泄漏。选择其中一行右击选择Path to GC Roots---->Exclude weak/soft references可以查看该对象在哪被引用。
最后可以看到被系统的a所持有,而这个又被MianFragmemnt4类下面的thi$0所持有。
对内存分析前最好有两份Hprof文件做对比。比如对一个Activity进行内存分析,一份是进入该Activity前的Hprof文件,一份是进入之后又退出Activity的Hprof文件,可以比较两份哪些对象的占有的内存有增加。
(2)Histogram展示了类型的数量和占有的内存
可以对比两张Histogram表查看哪些类型的变化。
一般实际开发中使用Dominator Tree分析内存情况多些。
最后
以上就是老实手链为你收集整理的内存分析的全部内容,希望文章能够帮你解决内存分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复