相关文章

Android性能优化系列

Java虚拟机系列

前言

要想做好内存优化工作,就要掌握两大部分的知识,一部分是知道并理解内存优化相关的原理,另一部分就是善于运用内存分析的工具。本篇就来介绍内存分析工具:Memory Monitor、Allocation Tracker和Heap Dump的使用方法。

1.Memory Monitor

在Android Studio(以下简称AS)中Android Monitor是一个主窗口,它包含了Logcat,、Memory Monitor、CPU Monitor、 GPU Monitor和Network Monitor。其中Memory Monitor可以轻松地监视应用程序的性能和内存使用情况,以便于找到被分配的对象,定位内存泄漏,并跟踪连接设备中正在使用的内存数量。Memory Monitor可以报告出你的应用程序的内存分配情况, 更形象的呈现出应用程序使用的内存。它的作用如下:

  • 实时显示可用的和分配的Java内存的图表。
  • 实时显示垃圾收集(GC)事件。
  • 启动垃圾收集事件。
  • 快速测试应用程序的缓慢是否与过度的垃圾收集事件有关。
  • 快速测试应用程序崩溃是否与内存耗尽有关。

1.1 使用Memory Monitor

在使用Memory Monitor之前要确保手机开启了开发者模式和USB调试。

使用的步骤为:

1.运行需要监控的应用程序。

2.点击AS面板下面的Android图标,并选择Monitors选项。

如果Memory Monitor已经运行,效果如下图所示(AS版本2.3.2)。

图中的标注的功能如下:

- Initiate GC(标识1):用来手动触发GC。

- Dump Java heap(标识2):保存内存快照。

- Start/Stop Allocation Tracking(标识3):打开Allocation Tracker工具(后面会介绍)。

- Free(标识4):当前应用未分配的内存大小。

- Allocated(标识5):当前应用分配的内存大小。

图中y轴显示当前应用的分配的内存和未分配的内存大小;x轴表示经过的时间。

1.2 大内存申请与GC

从上图可以看出,分配的内存急剧上升,这就是大内存分配的场景,我们要判断这是否是合理的分配的内存,是Bitmap还是其他的大数据,并且对这种大数据进行优化,减少内存开销。

接下来分配的内存出现急剧下降,这表示垃圾收集事件,用来释放内存。

1.3 内存抖动

内存抖动一般指在很短的时间内发生了多次内存分配和释放,严重的内存抖动还会导致应用程序卡顿。内存抖动出现原因主要是短时间频繁的创建对象(可能在循环中创建对象),内存为了应对这种情况,也会频繁的进行GC,因此综合起来就产生了内存抖动,产生了如上图般的锯齿状。

2.Allocation Tracker

Allocation Tracker用来跟踪内存分配,它允许你在执行某些操作的同时监视在何处分配对象,了解这些分配使你能够调整与这些操作相关的方法调用,以优化应用程序性能和内存使用。

Allocation Tracker能够做到如下的事情:

  • 显示代码分配对象类型、大小、分配线程和堆栈跟踪的时间和位置。
  • 通过重复的分配/释放模式帮助识别内存变化。
  • 当与 HPROF Viewer结合使用时,可以帮助你跟踪内存泄漏。例如,如果你在堆上看到一个bitmap对象,你可以使用Allocation Tracker来找到其分配的位置。

2.1 使用Allocation Tracker

AS和DDMS中都有Allocation Tracker,这里会·介绍AS中的Allocation Tracke如何使用。首先要确保要确保手机开启了开发者模式,并且开启了USB调试。

使用的步骤为:

1.运行需要监控的应用程序。

2.点击AS面板下面的Android图标,并选择Monitors选项。

3.点击Start Allocation Tracking按钮,这时Start Allocation Tracking按钮变为了Stop Allocation Tracking按钮。

4.操作应用程序。

5.点击Stop Allocation Tracking按钮,结束快照。这时Memory Monitor会显示出捕获快照的期间,如下图所示。

6.过几秒后就会自动打开一个窗口,显示当前生成的alloc文件的内存数据。

2.2 alloc文件分析

自动打开的alloc文件窗口如下图所示。

该alloc文件显示以下信息:

列 说明
Method 负责分配的Java方法
Count 分配的实例总数
Total Size 分配内存的总字节数

接着我们来分析标红框的内容,负责分配的Java方法为performLaunchActivity,内存分配序列为2369,分配的对象为ActivityThread,分配的实例总数为300个,分配内存的总字节数为10512。不了解performLaunchActivity方法和ActivityThread可以看Android深入四大组件这一系列的文章。

目前的菜单选项是Group by Method我们也可以选择 Group By Allocator,如下图所示。

为了更好的解释图中的信息,这里给出测试的代码,MainActivity和SecondActivity 的代码如下所示。

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button =(Button)findViewById(R.id.bt_next);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this,SecondActivity.class));
            }
        });
    }
}

SecondActivity.java

public class SecondActivity extends AppCompatActivity {
    private static Object inner;
    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.bt_next);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                createInnerClass();
                finish();
            }
        });
    }
    void createInnerClass() {
        class InnerClass {
        }
        inner = new InnerClass();
    }
}

其中SecondActivity是存在内存泄漏的,生成快照期间,我的操作就是在MainActivity和SecondActivity跳转了3次(点击button 共6次)。这时我们回过头来看上图的红框的信息,MainActivity总共分配了3个Intent实例,占用内存为192字节。SecondActivity总共分配了6个实例,占用内存为96字节,其中分配了3个匿名内部类OnClickListener的实例,3个InnerClass的实例。

我们可以选择列表中的一项,单击鼠标右键,在弹出的菜单中选择jump to the source就可以跳转到对应的源文件中。

除此之外,还可以点击Show/Hide Chart按钮来显示数据的图形化,如下图所示。

3.Heap Dump

Heap Dump的主要功能就是查看不同的数据类型在内存中的使用情况。它可以帮助你找到大对象,也可以通过数据的变化发现内存泄漏。

3.1 使用Heap Dump

打开Android Device Monitor工具,在左边Devices列表中选择要查看的应用程序进程,点击Update Heap按钮(装有一半绿色液体的圆柱体),在右边选择Heap选项,并点击Cause GC按钮,就会开始显示数据。我们每次点击Cause GC按钮都会强制应用程序进行垃圾回收,并将清理后的数据显示在Heap工具中。如下图所示。

从上图可以看出,Heap工具共有三个区域,分别是总览视图(标识1)、详情视图(标识2)和内存分配柱状图(标识2)。

3.2 总览视图

其中总览视图可以查看整体的内存情况,表中的显示信息如下所示。

列 说明
Heap Size 堆栈分配给该应用程序的内存大小
Allocated 已分配使用的内存大小
Free 空闲的内存大小
%Used 当前Heap的使用率(Allocated/Heap Size)
Objects 对象的数量

结合上表和上图,我们在总览视图获得的信息就是:堆栈分配给当前的应用程序的内存大小为2.346MB,已分配的内存为1.346MB,空闲的内存为1MB,当前Heap的使用率为57.37%,对象的数量为24058个。

3.3 详情视图

详细视图展示了所有的数据类型的内存情况,表中列的信息如下所示。

列 说明
Type 数据类型
Total Size 总共占用的内存大小
Smallest 将该数据类型的对象从小到大排列,排在第一个的对象所占用的内存
Largest 将该数据类型的对象从小到大排列,排在最后一个的对象所占用的内存
Median 将该数据类型的对象从小到大排列,排在中间的对象所占用的内存
Average 该数据类型的对象所占用内存的平均值

除了列的信息,还有行信息:

行 说明
free 内存碎片
data object 对象
class object 类
1-byte array (byte[],boolean[]) 1字节的数组对象
2-byte array (short[],char[]) 2字节的数组对象
4-byte array (object[],int[],float[]) 4字节的数组对象
6-byte array (long[],double[]) 8字节的数组对象
non-Java object 非Java对象

行信息中比较重要的是free,它与总览视图中的free的含义不同,它代表内存碎片。当新创建一个对象时,如果碎片内存能容下该对象,则复用碎片内存,否则就会从free空间(总览视图中的free)重新划分内存给这个新对象。free是判断内存碎片化程度的一个重要的指标。

此外,1-byte array这一行的信息也很重要,因为图片是以byte[]的形式存储在内存中的,如果1-byte array一行的数据过大,则需要检查图片的内存管理了。

3.4 检测内存泄漏

Heap Dump也可以检测内存泄漏。在左边Devices列表中选择要查看的应用程序进程,点击Update Heap按钮(装有一半绿色液体的圆柱体),在右边选择Heap选项,并点击Cause GC按钮,就会开始显示数据,如下图所示。

这时data object的Total Size为270.266KB。接下来操作应用,这个应用仍旧是在2.2小节所举的内存泄漏的例子,我反复的在MainActivity和SecondActivity跳转了10次(点击Button共20次),数据显示为:

data object的Total Size变为了768.172KB。这时我点击Cause GC按钮,数据显示为:

可以看到data object的Total Size变为了444.516KB,再点击一次Cause GC按钮:

Total Size变为了323.312KB,经过两次Cause GC的操作,Total Size的值从768.172KB变为了323.312KB,这是一个比较大的变化,说明在Cause GC操作之前有462.86KB(768.172KB-323.312KB)的内存没有被回收,可能发生了内存泄漏。

参考资料

Memory Monitor

Allocation Tracker

Android Monitor Basics

Android性能专项测试之Memory Monitor工具

《Android应用性能优化最佳实践》

《Android群英传 神兵利器》

《高性能Android应用开发》

Android内存优化(四)解析Memory Monitor、Allocation Tracker和Heap Dump的更多相关文章

  1. Android内存优化(二)解析Memory Monitor、Allocation Tracker和Heap Dump

    前言 要想做好内存优化工作,就要掌握两大部分的知识,一部分是知道并理解内存优化相关的原理,另一部分就是善于运用内存分析的工具.本篇就来介绍内存分析工具:Memory Monitor.Allocatio ...

  2. Android 性能优化(23)*性能工具之「Heap Viewer, Memory Monitor, Allocation Tracker」Memory Profilers

    Memory Profilers In this document Memory Monitor Heap Viewer Allocation Tracker You should also read ...

  3. Android内存优化7 内存检测工具1 Memory Monitor检测内存泄露

    上篇说了一些性能优化的理论部分,主要是回顾一下,有了理论,小平同志又讲了,实践是检验真理的唯一标准,对于内存泄露的问题,现在通过Android Studio自带工具Memory Monitor 检测出 ...

  4. 【腾讯Bugly干货分享】Android内存优化总结&实践

    本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/2MsEAR9pQfMr1Sfs7cPdWQ 导语 智 ...

  5. Android内存优化(三)详解内存分析工具MAT

    前言 在这个系列的前四篇文章中,我分别介绍了DVM.ART.内存泄漏和内存检测工具的相关知识点,这一篇我们通过一个小例子,来学习如何使用内存分析工具MAT. 1.概述 在进行内存分析时,我们可以使用M ...

  6. Android内存优化(一)DVM和ART原理初探

    相关文章 Android内存优化系列 Java虚拟机系列 前言 要学习Android的内存优化,首先要了解Java虚拟机,此前我用了多篇文章来介绍Java虚拟机的知识,就是为了这个系列做铺垫.在And ...

  7. Android内存优化杂谈

    Android内存优化是我们性能优化工作中比较重要的一环,这里其实主要包括两方面的工作: 优化RAM,即降低运行时内存.这里的目的是防止程序发生OOM异常,以及降低程序由于内存过大被LMK机制杀死的概 ...

  8. ANDROID内存优化——大汇总(转)

    原文作者博客:转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! ANDROID内存优化(大汇总——上) 写在最前: 本文的思路主要借鉴了20 ...

  9. Android内存优化1 了解java内存分配 1

    开篇废话 今天我们一起来学习JVM的内存分配,主要目的是为我们Android内存优化打下基础. 一直在想以什么样的方式来呈现这个知识点才能让我们易于理解,最终决定使用方法为:图解+源代码分析. 欢迎访 ...

随机推荐

  1. LeetCode——Integer Break

    Question Given a positive integer n, break it into the sum of at least two positive integers and max ...

  2. centos7 firewall 操作

    一.firewall配置 The configuration for firewalld is stored in various XML files in /usr/lib/firewalld/ a ...

  3. Java实习二

    链表(java实现) Link.java public class Link{ private Node first; public Link(){ this.first = null; } //判断 ...

  4. 转载:hdu 题目分类 (侵删)

    转载:from http://blog.csdn.net/qq_28236309/article/details/47818349 基础题:1000.1001.1004.1005.1008.1012. ...

  5. 07_ZkClient提供的API使用

    1. ZkClient API简介 zkclient是Github上一个开源的ZooKeeper客户端,在原生ZooKeeper API接口上进行包装,同时在内部实现了session超时重连,Watc ...

  6. 06_zookeeper_原生API使用2

    1. 设置znode节点数据(同步) import org.apache.zookeeper.*; import org.apache.zookeeper.data.Stat; import java ...

  7. 设计模式——迭代器(Iterator)模式

    概述 迭代器模式简单的说(按我目前的理解)就是一个类提供一个对外迭代的接口,方面调用者迭代.这个迭代接口至少包括两个方法:hasNext()--用于判断是否还有下一个,next()--用于取出下一个对 ...

  8. PHP数组合并:[“+”运算符]、[array_merge]、[array_merge_recursive]区别

    1.“+”运算符规则: 当两个数组的键名是数字键名或者字符串键名 $c = $a + $b 在$a后追加($b在$a中不存在的键名)键名和值注意: 1.不覆盖,只是追加不存在的键名和对应的值 2.键名 ...

  9. Java 类的构造器的调用顺序

    规则如下: 对于一个复杂的对象,构建器的调用遵照下面的顺序: (1) 调用父类构建器.这个步骤会不断重复下去,首先得到构建的是分级结构的根部,然后是下一个子类,等等.直到抵达最深一层的子类. (2) ...

  10. spring mvc:输出json,输出多个json

    spring mvc:输出xml/输出json 用到的注解@ResponseBody @ResponseBody用来输出json/xml等格式数据(非html) controller输出用到的类 or ...