内存分析

 本文介紹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是打不开,要先进行转换。

在androidSdk\platform-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分析内存情况多些。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值