Android应用程序内存分析

原文链接:http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html

Dalvik 自带有内存回收机制,但这并不意味程序员可以忽略内存的管理。在移动设备上,内存比较紧缺,因此你应当对内存的使用更加小心。在本文中,我们将介绍如何使用android SDK中的内存分析工具来对应用程序的内存使用情况进行分析。

有些内存问题是显而易见的。例如,如果应用程序在每次用户触摸屏幕时都会泄漏一些内存,那么该应用将很快因为 OutOfMemoryError的异常而崩溃。另外一些则更加隐蔽,它们有可能只会导致应用程序和整个系统变慢(垃圾回收器频繁和长时间进行垃圾回收)

调试工具

在android SDK中提供了两种内存分析的方法:内存申请跟踪(以下用Allocation tracker) 和 堆转储(以下用heap dump)。Allocation tracker可以帮我们了解到一段时间内,应用对内存的申请情况,但是它不能提供任何有关应用程序堆的信息。更多有关内存申请追踪的信息请看 Tracking Memory Allocations。接下来的篇幅中我们将重点关注一种更加强有力的分析工具——heap dump的使用。

Heap dump是应用程序堆的的快照,它存放在一种特定格式(HPROF)的二进制文件中。Dalvik使用类似于HPROF的格式来保存heap dump。生成应用程序的heap dump的方法有多种,DDMS中的head dump按钮就提供了生成heap dump的功能。如果想要对heap dump的生成有更加精细的控制,可以在程序中使用android.os.Debug.dumpHprofData()来生成。

常用的分析heap dump的工具有jhat 和 Eclipse Memory Analyzer (MAT) 。在分析之前,我们需要将Dalivk heap dump文件的格式转换成J2SE 标准的HPROF格式。android SDK中提供了hprof-conv工具来进行这个转换。命令如下:

hprof-conv dump.hprof converted-dump.hprof

例子:如何分析内存泄漏

在Dalivk环境中,程序员不能显式的申请和释放内存,因此内存不会像在C/C++中的那样真正泄漏。在这种情况下,内存泄漏往往指的是程序中保存了无用的对象的引用,有时保存一个对象的引用,而这个对象又拥有大量其他对象的引用,那么这些对象将都无法被垃圾回收器回收。

让我们看android SDK中的一个示例程序Honeycomb Gallery sample app。这是一个用来展示如何使用android Honeycomb 中的新API的照片库应用(如何下载和编译这个应用的代码,请看介绍)。我们将小心的在这个应用的代码中加入一个内存泄漏的bug,以讲述如何调试这样的问题。

假如我们想修改这个应用,让其具有从网络上下载图片的能力。为了提升体验,我们决定实现一个缓存以存储最近收到的图片,我们通过对ContentFragment.java文件进行一些小的修改来实现这个想法。首先在这个类的顶部加上一个静态的变量

private static HashMapsBitmapCache = new HashMap();

这个变量将保存我们想要缓存的图片,现在我们修改updateContentAndRecycleBitmap() 加入检查存储和存入缓存的功能

void updateContentAndRecycleBitmap(int category, int position) {

if (mCurrentActionMode != null) {

mCurrentActionMode.finish();

}

// Get the bitmap that needs to be drawn and update the ImageView.

// Check if the Bitmap is already in the cache

String bitmapId = "" + category + "." + position;

mBitmap = sBitmapCache.get(bitmapId);

if (mBitmap == null) {

// It's not in the cache, so load the Bitmap and add it to the cache.

// DANGER! We add items to this cache without ever removing any.

mBitmap = Directory.getCategory(category).getEntry(position)

.getBitmap(getResources());

sBitmapCache.put(bitmapId, mBitmap);

}

((ImageView) getView().findViewById(R.id.image)).setImageBitmap(mBitmap);

}

这里,我故意留下了一个memory leak的问题:我们将Bitmap添加到cache但是却从来不从cache中删除它们。在真正的应用中,往往会对cache的大小进行一个限制。

使用DDMS来分析内存使用情况

DDMS是android最主要的一个调试工具,它是ADT插件的一部分,同时在android SDK的tools/ directory目录下也有一个独立的版本。更对关于DDMS的信息,请看Using DDMS

让我们使用DDMS来分析内存使用情况。DDMS有两种启动方式:

从Eclipse:点击Window > Open Perspective > Other... > DDMS

从命令行:在tools/ directory中执行ddms命令

在左边的面板里选择进程com.example.android.hcgallery,然后点击工具栏上的Show heap updates按钮,之后切换到DDMS中的VM Heap页。这里显示了堆内存的基本状态信息,这些信息每次GC时更新。点击Cause GC按钮可以触发第一次更新。

可以看到,我们使用了8MB多一点的内存,现在滑动相册,看到这个数字会变大。由于应用中总共只有13張图片,因此我们不会无限制的泄漏内存。从某种意义上来说,这是一种最糟糕的泄漏,因为我们永远也不会收到OutOfMemoryError的异常来帮助我们发现这个问题。

创建一个heap dump

让我们使用heap dump来定位这个问题。点击中DDMS工具栏上的Dump HPROF按钮,选择一个保存路径,然后运行hprof-conv处理这个文件。在这个例子中,我将使用MAT的独立应用版本(版本号1.0.1),下载链接MAT download site

如果你正在使用ADT并且Eclipse中已经安装了MAT插件,点击dump HPROF按钮,工具将会自动对HPROF文件进行格式转换,然后直接在Eclipse中使用MAT打开转换后的HPROF文件。

使用MAT分析heap dump

启动MAT,打开我们转换过的HPROF文件。MAT是个强大的工具,拥有很多功能。在这篇文章中,我只介绍一种使用它来分析内存问题的方法:Histogram view。Histogram view显示了堆中所有类的列表,我们可以将列表中这些类按照其实例(object)的个数的多少排序(包括按照浅堆中实例的个数和深堆中实例的个数)

如果我们按照浅堆排序,我们可以看到byte[]类型排在第一位,这是因为在android3.0中bitmap的像素点数据都保存在byte数组中(之前它们都没有被保存在dalik的堆空间中),基于这些数组的大小,我们可以断言,这些数组就是我们泄漏的bitmap内存的一部分。

在列表中右击byte[]类型,在弹出菜单中依次选择List Objects > with incoming references,可以看到,在之前视图中我们点击的类型对应的所有浅堆中的byte array对象都被列了出来。

选择其中一个比较大的对象,点击箭头查看下拉列表中的内容,这里我们可以看到这个对象的整条引用链,其中可以找到我们的bitmap cache。

MAT不能明确的告诉我们哪里发生了泄漏,因为它并不知道这些对象是否还在使用——仅仅只有程序员知道这一点。在这个例子中,缓存占用了应用程序大量的内存,因此在这种情况下,我们应该考虑对cache的大小进行限制。

使用MAT对heap dump进行比较

有时比较两个不同时间点的heap dump对我们分析内存泄漏问题是很有帮助的。首先,我们需要生成两个heap dump文件(别忘记使用 hprof-conv进行转换)

接下来我们可以使用MAT进行比较了(过程稍稍有些复杂)

打开第一个HPROF 文件(使用 File > Open Heap Dump)

打开Histogram view

在Navigation History view中(如果找不到使用 Window > Navigation History打开), 对其中的histogram条目右击,然后选择Add to Compare Basket.

重复2~3步骤,打开第二个HPROF文件

切换到Compare Basket 页,点击Compare the Results按钮(这页右上角的红色按钮)

总结

在本文中,我展示了如何通过Allocation Tracker 和 heap dumps 这两个工具来

更好的认识

应用内存的使用情况有。我也展示了如何使用MAT来追踪应用中的内存泄漏问题。MAT是个强大的工具,而我在这里仅仅只是提到了它的皮毛。如果你想要了解更多相关内容,我建议你阅读下面的文章

Memory Analyzer News: Eclipse MAT官方blog

Markus Kohler 的java性能分析博客有很多有用的文章, 包括 Analysing the Memory Usage of Android Applications with the Eclipse Memory Analyzer 和10 Useful Tips for the Eclipse Memory Analyzer.

android应用内存分析,Android应用程序内存分析-Memory Analysis for Android Applications相关推荐

  1. java 减少内存_java-减少应用程序内存占用

    >如果经常重复使用具有自然语言频率的字符串,请不要对同一字符串使用新的对象实例. private Map sharedStrings = new HashMap<>(). publi ...

  2. php采集分析,PHP采集程序原理分析篇

    由于需要,要写一个简单的PHP采集程序,照例是到网上找了一堆教程,然后照猫画虎,可是发现网上的教程全是似是而非,没有一个真正能用的.苦想了几天,终于弄明白了里面的道理.在这里写出来,请高手指正. 采集 ...

  3. linux c 代码分析工具,编程达人 分享几款Linux 下C/C++程序内存泄漏检查工具

    1.内存管理是否正确(因为这个程序本身开辟很多内存空间进行缓存管理,同时这个程序程序本身就是基于C/C++开发的,内存管理机制一直是程序员头痛的东西) 2.程序的健硕性如何(服务器任何程序的基本要求就 ...

  4. Wince程序内存和存储内存

    Wince 下的内存实际上是分为三个部分的. 先说这几部分的名字,对象存储, 系统内存,程序内存. 准确来讲,应该用下面公式说明Wince内存 = 系统内存 + (对象存储 + 程序内存).这里德内存 ...

  5. oracle 内存分析工具,IDE 中的分析工具

    IDE 中的分析工具 Oracle Solaris Studio IDE 提供的交互式图形分析工具可用于检查在 IDE 内部运行的项目的性能.分析工具使用 Oracle Solaris Studio ...

  6. Linux 下几款程序内存泄漏检查工具

    Linux 下几款程序内存泄漏检查工具 chenyoubing | 发布于 2016-07-23 10:08:09 | 阅读量 93 | 无 写这篇博客的原因呢是因为自己在编写基于Nginx磁盘缓存管 ...

  7. Unix下C程序内存泄露检测工具:valgrind的安装使用

    Valgrind是一款用于内存调试.内存泄漏检测以及性能分析的软件开发工具. Valgrind的最初作者是Julian Seward,他于2006年由于在开发Valgrind上的工作获得了第二届Goo ...

  8. 《小猫猫大课堂》三轮5——动态内存管理(通讯录动态内存化)

    宝子,你不点个赞吗?不评个论吗?不收个藏吗? 最后的最后,关注我,关注我,关注我,你会看到更多有趣的博客哦!!! 喵喵喵,你对我真的很重要. 目录 前言 动态内存产生的原因 动态内存函数 malloc ...

  9. 【Android 逆向】修改运行中的 Android 进程的内存数据 ( 使用 IDA 分析要修改的内存特征 | 根据内存特征搜索修改点 | 修改进程内存 )

    文章目录 一.使用 IDA 分析要修改的内存特征 二.根据内存特征搜索修改点 三.修改进程内存 一.使用 IDA 分析要修改的内存特征 在前的博客 [Android 逆向]逆向修改游戏应用 ( 分析应 ...

最新文章

  1. linux putty xshell vi 小键盘无法使用的解决方法
  2. c 语言文字输出函数,c/c++语言中文字输出函数总结
  3. OpenGL编程指南1:OpenGL简介
  4. VTK:BackfaceCulling背面剔除用法实战
  5. 在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口 6...
  6. 数据结构之图的存储结构:邻接多重表
  7. 设计一个扩展自抽象类geometricobject的新的triangle类_面向对象设计原则之开放封闭原则(开闭原则OCP)...
  8. 《Cisco防火墙》一8.7 通过NAT规则定义连接限制
  9. 【数据结构和算法笔记】:图的深度优先搜索(DFS)
  10. 鲍尔默先生,请拿出证据
  11. ad17如何删除3d实体_3D打印的过程/流程
  12. pandas.series.tolist()函数结构及用法
  13. 贪心算法3: 会议安排
  14. python卡方检验计算pvalue值_Python数据科学:卡方检验
  15. linux dot命令,DOT语言使用笔记(1)
  16. 遗传图谱的可视化(比mapchart更强大)
  17. js如何修改对象的padding属性
  18. 全国计算机等级考试二级Java全真模拟
  19. NLP(三十九)使用keras-bert实现完形填空及简单的文本纠错功能
  20. NET Framework合集(官方)

热门文章

  1. 【SpringCloud】配置中心简介及其搭建
  2. RuntimeError: Found dtype Double but expected Float”
  3. Python视频处理库:scikit-video
  4. 观点 | 商汤科技联合创始人林达华:深度学习遭遇瓶颈,未来之路需要新的思考
  5. python 背景建模高斯混合模型
  6. Python+OpenCV学习(17)---摄像机标定
  7. 傅里叶变换时间复杂度
  8. php接收一维数组中文乱码解决
  9. ubuntu 使用FFTW快速计算离散傅里叶变换
  10. 36 多线程之线程池pool