韩梦飞沙 yue31313 韩亚飞 han_meng_fei_sha 313134555@qq.com

需要 获取 root 权限

步骤:

1,使用eclipse 自带的 DDMS 工具分析各线程的内存使用情况,如下图所示

Heap视图界面会定时刷新,在对应用的不断的操作过程中就可以看到内存使用的变化。

怎样判断当前进程是否有内存泄漏呢?

这里需要注意一个值:VM Heap页面中部有一个data object选项,即数据对象,也就是我们的程序中大量存在的类类型的对象。

在data object一行中有一列是“Total Size”,其值就是当前进程中所有Java数据对象的内存总量,一般情况下,这个值的大小决定了是否会有内存泄漏。如上图中选中行所示。

可以据此判断内存有泄漏:
1) 不断的操作当前应用,或者重复某一动作,注意观察data object的Total Size值。

2) 正常情况下Total Size值都会稳定在一个有限的范围内,也就是说如果程序中的的代码逻辑良好,

没有创建的对象不被GC机制正常回收的情况,即便 我们不断的操作生成很多对象,而在虚拟机不断的进行垃圾回收的过程中,这些对象都被正常回收了,内存使用量会保持在一个比较稳定的水平。

3) 如果代码中存在对象引用没有释放的情况,则data object的Total Size值在每次GC后不会有明显的回落,随着操作次数的增多Total Size的值会越来越大。
正常情况下,一个虚拟机的进程的内存在64M, 如果内存泄漏会发现 Heap Size 在不断的逼近 64M, 一旦达到这个值时,就会出现退出应用等情况。

发生内存泄露,Total Size的值越来越大时,按下“Dump HPROF file”按钮,这个时候会提示设置hprof文件的保存路径。保存后,可以对比log来分析是哪些操作造成了内存泄漏。

2,点击 按钮,导出 hprof 文件,使用MAT 工具进行分析。具体分析步骤和过程详见下面链接

http://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-ma/index.html

3,打开 MAT 工具,File-->Open Heap Dump... 选择你刚刚保存的 hprof 文件打开

此时,会弹出一个错误,如下图所示:

提示:  Unknown HPROF Version (JavaPROFILE 1.0.3) (java.io.IOException)

哦,不要以为是 MAT 工具版本不对,其实是 Android 的 hprof 文件在这里需要进行转换一下格式才可以使用 MAT 打开,不知道 谷歌在这里

捣了什么鬼,难道是优化?

使用 android sdk 目录下的 tools 中一个工具进行转化一下

4,使用AndrodiSDK/tools/hprof-conv转化hprof文件,

首先,要通过控制台进入到你的 android sdk tools 目录下

例如 hprof-conv input.hprof     out.hprof

再使用MAT工具打开转换后的 hprof 文件,就能看到完整的内存使用分析报告了。

如下所示是 MAT 分析内存使用的主界面:

点击上图中的 Reports -->Leak Suspects 则可以进一步看到更详细的内存泄漏疑点。

在其中怀疑的地方,点击 Details 就可以看到具体的内存使用情况了。

tip1:

有一种比较好的方法是,在内存泄漏开始时抓取一个 hprof 文件,在内存泄漏很厉害时,app 濒临崩溃时再抓取一个hprof 文件。

对比看这两个图,就很容易看出来上面的饼图中哪一块存在内存泄漏。

有的时候能直接看出来多了一块。那么我们就从那一块入手进行分析。比较快能得到结果。

tip2:

看 dominator_tree,可以从列表中 data_object 最多的几项数据入手分析,如下文件所示(136,80对应的两项)

我这边曾经就因为在 onStart 中添加了一个 PhoneStateListener 的监听,而在 onStop 中未设置为空,导致内存泄漏。

这里引用一点别人总结的实例:

原因1:

BraodcastReceiver,ContentObserver,FileObserver,Cursor在Activity onDeatory或者某类声明周期结束之后一定要unregister或者close掉,否则这个Activity类会被system强引用,不会被内存回收。

原因2:

不要直接对Activity进行直接引用作为成员变量,如果不得不这么做,请用private WeakReference mActivity来做,相同的,对于Service等其他有自己声明周期的对象来说,直接引用都需要谨慎考虑是否会存在内存泄露的可能。()

  1. private static class MyHandler extends Handler {
  2. private WeakReference<GeneralSettings> mStatus;
  3. public MyHandler(GeneralSettings activity) {
  4. mStatus = new WeakReference<GeneralSettings>(activity);
  5. }
  6. @Override
  7. public void handleMessage(Message msg) {
  8. GeneralSettings status = mStatus.get();
  9. if (status == null) {
  10. return;
  11. }
  12. switch (msg.what) {
  13. case EVENT_UPDATE_STATS:
  14. status.updateTimes();
  15. sendEmptyMessageDelayed(EVENT_UPDATE_STATS, 1000);
  16. break;
  17. }
  18. }
  19. }
  1. private static class MyHandler extends Handler {
  2. private WeakReference<GeneralSettings> mStatus;
  3. public MyHandler(GeneralSettings activity) {
  4. mStatus = new WeakReference<GeneralSettings>(activity);
  5. }
  6. @Override
  7. public void handleMessage(Message msg) {
  8. GeneralSettings status = mStatus.get();
  9. if (status == null) {
  10. return;
  11. }
  12. switch (msg.what) {
  13. case EVENT_UPDATE_STATS:
  14. status.updateTimes();
  15. sendEmptyMessageDelayed(EVENT_UPDATE_STATS, 1000);
  16. break;
  17. }
  18. }
  19. }

原因3:

对 Context 保持了一个长生命周期的引用。

  1. private static Drawable sBackground;
  2. @Override
  3. protected void onCreate(Bundle state) {
  4. super.onCreate(state);
  5. TextView label = new TextView(this);
  6. label.setText("Leaks are bad");
  7. if (sBackground == null) {
  8. sBackground = getDrawable(R.drawable.large_bitmap);
  9. }
  10. label.setBackgroundDrawable(sBackground);
  11. setContentView(label);
  12. }
  1. private static Drawable sBackground;
  2. @Override
  3. protected void onCreate(Bundle state) {
  4. super.onCreate(state);
  5. TextView label = new TextView(this);
  6. label.setText("Leaks are bad");
  7. if (sBackground == null) {
  8. sBackground = getDrawable(R.drawable.large_bitmap);
  9. }
  10. label.setBackgroundDrawable(sBackground);
  11. setContentView(label);
  12. }

sBackground的生命周期比Activity要长,label引用到context,sBackground又把label设为内部成员变量,所以sBackground引用到了context,导致activity结束的时候context还是不能释放,从而引发内存泄露。(不甚理解,还要仔细研究一下)

总结:

1.      对activity的引用应该控制在activity的生命周期之内;

2.      如果不能就考虑使用getApplicationContext或者getApplication;

3.      尽量不要在静态变量或者静态内部类中使用非静态外部成员变量(包括context),即使要使用,也要考虑适时把外部成员变量置空(如上例可以通过把sBackground的callback置空来解决内存泄露的问题);也可以在内部类中使用弱引用来引用外部类的变量;

4.      做到在onDestroy中释放资源,如清空对图片等资源有直接引用或者间接引用的数组(使用array.clear();array = null);

安卓 内存泄漏 MemoryAnalyzer的更多相关文章

  1. 安卓 内存 泄漏 工具 LeakCanary 使用

    韩梦飞沙 yue31313 韩亚飞 han_meng_fei_sha 313134555@qq.com LeakCanary是Square开源了一个内存泄露自动探测神器 .这是项目的github仓库地 ...

  2. 安卓 内存泄漏检测工具 LeakCanary 使用

    韩梦飞沙 yue31313 韩亚飞 han_meng_fei_sha 313134555@qq.com 配置 build.gradle dependencies { debugCompile 'com ...

  3. eclipse java MemoryAnalyzer 查询内存泄漏 环境配置

    简单记录下java用MemoryAnalyzer分析内存泄漏问题! 首先,内存不足的时候,会报错 Exception in thread "main" java.lang.OutO ...

  4. 安卓android WebView Memory Leak WebView内存泄漏

    Android WebView Memory Leak WebView内存泄漏 在这次开发过程中,需要用到webview展示一些界面,但是加载的页面如果有很多图片就会发现内存占用暴涨,并且在退出该界面 ...

  5. java内存泄漏的定位与分析

    1.为什么会发生内存泄漏 java 如何检测内在泄漏呢?我们需要一些工具进行检测,并发现内存泄漏问题,不然很容易发生down机问题. 编写java程序最为方便的地方就是我们不需要管理内存的分配和释放, ...

  6. 使用Memory Analyzer tool(MAT)分析内存泄漏(二)

    转载自:http://www.blogjava.net/rosen/archive/2010/06/13/323522.html 前言的前言 写blog就是好,在大前提下可以想说什么写什么,不像投稿那 ...

  7. 使用Memory Analyzer tool(MAT)分析内存泄漏

    前言的前言 写blog就是好,在大前提下可以想说什么写什么,不像投稿那么字字斟酌.上周末回了趟成都办事,所以本文来迟了.K117从达州经由达成线往成都方向走的时候,发现铁路边有条河,尽管我现在也不知道 ...

  8. Android内存泄漏分析

    周末去上海参加了安卓巴士组织的技术论坛,去了才发现自己基础很渣..... 其中提到了android的内存泄漏的问题,回来马上度娘(虽说度娘很渣),整理如下: 一.单例造成的内存泄漏 因为单例的静态特性 ...

  9. (转)java内存泄漏的定位与分析

    转自:http://blog.csdn.net/x_i_y_u_e/article/details/51137492 1.为什么会发生内存泄漏 java 如何检测内在泄漏呢?我们需要一些工具进行检测, ...

随机推荐

  1. Item27--优先考虑泛型方法

    类型推导:发生在以下三个地方.1.Java编译器根据泛型方法传入的参数,推导出具体的类型.2.Java编译器,根据泛型构造器传入的类型来推导出实际要构造的实例类型.3.Java编译器根据表达式的目标类 ...

  2. 【BZOJ】1666 [Usaco2006 Oct]Another Cow Number Game 奶牛的数字游戏

    [算法]贪心&&堆 [题解]反过来看就是合并任意两块木板,花费为木板长度之和. 显然从最小的两块开始合并即可,用堆(优先队列)维护. 经典DP问题石子归并是只能合并相邻两堆石子,所以不 ...

  3. 彻底解决_OBJC_CLASS_$_某文件名", referenced from:问题

    最近在使用静态库时,总是出现这个问题.下面总结一下我得解决方法: 1. .m文件没有导入    在Build Phases里的Compile Sources 中添加报错的文件 2. .framewor ...

  4. 【洛谷 P4116】 Qtree3 (树链剖分)

    题目链接 树剖练手题,想复习下树剖. 第一次提交\(T\)成QQC 看我 ??? 看了数据范围的确挺恶心的,我的复杂度是\(O(Mlog^2N)\)的,数据范围有三段 For 1/3 of the t ...

  5. 大聊Python----进程和线程

    什么是线程? 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. ...

  6. elementui table 多选 获取id

    //多选相关方法 toggleSelection(rows) { if (rows) { rows.forEach(row => { this.$refs.multipleTable.toggl ...

  7. Fiddler抓取HTTPS协议

    HTTPS协议握手过程: 1,客户端明文请求,把自己支持的非对称加密算法(用于使用CA证书公钥加密计算生成协商密钥的随机数per_master).对称加密算法(用于以后使用协商密钥加密传输内容).验证 ...

  8. 为什么Windows7打开项目的方式是灰的不能修改

    http://jingyan.baidu.com/article/d3b74d64a964691f77e60900.html 进入组策略编辑器,即运行gpedit.msc,进入“用户配置”-“管理模板 ...

  9. Linux typeof【转】

    转自:http://blog.csdn.net/xiaofeng_yan/article/details/5248633 今天偶然又看到了typeof这个东西,只知道它大概是返回变量的类型,后来上网查 ...

  10. 自动化测试===requests+unittest+postman的接口测试

    postman是一个跨平台的接口测试工具,下载链接在这里:https://www.getpostman.com/ unittest是一个单元测试框架,python中安装:pip install uni ...