内存溢出,是Android开发中常遇到的问题,解决起来总是摸不着头脑。今天爬爬就来讲讲如何定位内存溢出。

1. OOM(内存溢出)和Memory Leak(内存泄露)有什么关系?

OOM可能是因为Memory Leak,也可能是你的应用本身就比较耗内存(比如图片浏览型的,或者应用本身的设计有问题)。所以,出现OOM不一定是Memory Leak。

同样,Memory Leak也不一定就会导致OOM,如果泄露的速度很慢,可能还没用完可用内存应用就被重启了,那就不会OOM咯。当然了,有bug解决了最好。

2. 什么是shallow heap与retained heap?

  • shallow heap:你自身占了多少内存,比如你有一个int属性,就占4字节。不包括你引用的其他对象。
  • retained heap:如果你被销毁,总共会释放多少内存。这些因你存在被占据的空间就是retained heap。
  • 更详细的解释请看这篇博客

3. 什么是GC roots?

GC的时候,是从这些节点开始遍历,不停的寻找其子节点直到结束。然后把不能遍历到的节点释放。这些遍历的起点(注意,可不是一个哦)就叫做GC roots。

那,对于java来说,谁是GC roots?简单点说(不是那么准确)包括以下几种:

  • 栈上面的局部变量
  • 栈上面的函数参数变量
  • 所有由Bootstrap Loader加载的类变量
  • 另外,JNI相关的也会有
  • 更多详细解释请看这篇博客

其实到最后,谁是GC roots不是那么重要,因为一般来说,到最后就剩下一些系统框架类,以及jvm和class相关的东西。这里给大家说GC roots主要是因为使用mat需要了解它。

4. 怎样使用MAT定位内存泄露?

4.1 看Histogram(类统计图)

histogram视图显示了每个类有多少实例,并可以按照这些实例占据的Retained size和Shallow size排序。通过过滤包名,很容易发现有问题的类。

这里有几个简单的原则,比如,activity的实例通常只应该有一个。已经关闭的activity不应该出现。实体类的Retained size应该是比较小的,也就几十KB。

对于Android程序来说,内存泄露通常都会牵扯到activity。因此,dump之前,可以多旋转几次屏幕并反复的进出可能有问题的activity,让问题尽可能的凸现。
通过Histogram我们可以看每个类有多少个实例,shallow和retained heap分别有多大。如果只是看java的基础类型和framework的类,没有什么意义,一定要过滤出自己的类型,如下图

发现LeakInnerClassActivity产生了9个实例,一定是被hold住了。

4.2 看Dominator Tree

大家来看这个图,左侧是对象引用关系,右侧是dominator tree

  • Note that A, B and C are dominated by a “virtual” root object.
  • Note that the dominator relationship is transitive;C dominates E which dominates G therefore C also dominates G.

这个视图非常强大,它把所有实例按Retained heap和Shallow heap列出来;并且,只要展开就可以看到这个实例所占有的实例(换句话说,如果该对象被释放,还会有哪些对象被释放)

使用这个视图,可以很方便的追踪被泄露的内存到底是谁占用了,更多参考这篇博客

4.3 对比heap dumps,可以更快的定位内存泄露的位置。操作步骤:

  • 打开一个HPROF文件,切换到histogram视图
  • 在Navigation View中右键点击histogram,选择Add to compare basket
  • 打开另一个HPROF文件,并重复上一个步骤
  • 对比两次heap dumps的内容,看下图,LeakInnerClassActivity的实例又增加了一个。而我仅仅是又启动了一次该Activity,所以问题显而易见。

参考:Memory Analysis for Android Applications

5. 内部类怎样使用才会产生内存泄露,以及由此衍生的AsyncTask、Handler问题如何解决?

  • 如果非静态内部类的方法中,有生命周期大于其所在类的,那就有问题了。比如:AsyncTask、Handler,这两个类都是方便开发者执行异步任务的,但是,这两个都跳出了Activity/Fragment的生命周期。(或许,是时候学习Loader了)
  • 为什么?因为非静态内部类会自动持有一个所属类的实例,如果所属类的实例已经结束生命周期,但内部类的方法仍在执行,就会hold其主体。也就使主体不能被释放,亦即内存泄露。
  • 静态类呢?静态类编译后和非内部类是一样的,有自己独立的类名。不会悄悄引用所属类的实例,所以就不容易泄露。
//首先,静态类
static class IncomingHandler extends Handler {//其次,弱引用private final WeakReference<UDPListenerService> mService; IncomingHandler(UDPListenerService service) {mService = new WeakReference<UDPListenerService>(service);}@Overridepublic void handleMessage(Message msg) {UDPListenerService service = mService.get();if (service != null) {service.handleMessage(msg);}}
}

6. 图片导致的OOM如何解决?

  • 加载时使用option,用多大,载入多大。
  • res目录下的图片也是一样,及时清理过大的图片资源。
  • 如果还有问题,就想办法把不可见的资源释放掉,比如,TabActivity中不可见的Tab,ViewPager中的Fragment。
  • 如果activity的图片资源较多,需要考虑屏幕旋转时,销毁已有资源。请参考这篇文章

7. 需要context的时候用activity还是application?

  • 看使用的周期是否在activity周期内,如果超出,必须用application;常见的情景包括:AsyncTask,Thread,第三方库初始化等等。
  • 还有些情景,只能用activity:比如,对话框,各种View,需要startActivity的等。
  • 总之,尽可能使用Application。参考stackoverflow

8. 什么时候需要手动将变量设置为NULL?

  • 类变量,一旦用完,尽快释放。因为类的存活时间最长(非常长),所以,占用的资源越少越好;
  • 比较耗时且耗内存的方法内的局部变量,比如,图片处理的方法,每个bitmap对象用完就及时丢弃。尽可能早的让gc介入。

参考:http://kohlerm.blogspot.com/

Android内存溢出分析相关推荐

  1. android释放acitity内存,Android 内存泄漏分析与解决方法

    在分析Android内存泄漏之前,先了解一下JAVA的一些知识 1. JAVA中的对象的创建 使用new指令生成对象时,堆内存将会为此开辟一份空间存放该对象 垃圾回收器回收非存活的对象,并释放对应的内 ...

  2. Android 内存泄漏分析指北

    android 内存泄漏分析指北 简单来说内存泄漏就是当对象不再被应用程序使用,但是垃圾回收器却不能移除它们,因为它们正在被引用 java 垃圾回收介绍: Java 虚拟机运行所管理的内存包括以下几个 ...

  3. 内存溢出分析之工具篇

    内存溢出分析之工具篇 转载于:https://www.cnblogs.com/lwmp/p/9850446.html

  4. JVM 调优实战--jmap的使用以及内存溢出分析

    目录 jmap的使用以及内存溢出分析 查看内存使用情况 查看内存中对象数量及大小 将内存使用情况dump到文件中 通过jhat对dump文件进行分析 通过MAT工具对dump文件进行分析 MAT介绍 ...

  5. java内存溢出分析工具:jmap使用实战

    java内存溢出分析工具:jmap使用实战 在一次解决系统tomcat老是内存撑到头,然后崩溃的问题时,使用到了jmap.  1 使用命令  在环境是linux+jdk1.5以上,这个工具是自带的,路 ...

  6. Android内存泄漏分析及调试

    2019独角兽企业重金招聘Python工程师标准>>> Android内存泄漏分析及调试 分类: Android2013-10-25 11:31 5290人阅读 评论(5) 收藏 举 ...

  7. linux环境下内存溢出分析MAT

    文章目录 1 下载及安装mat 1.1 下载地址 1.2 查看服务器版本 1.3 下载安装 2 配置 3 运行 4 分析 1 下载及安装mat 1.1 下载地址 https://www.eclipse ...

  8. Android 内存泄漏分析与解决方法

    Android 内存泄漏分析与解决方法 参考文章: (1)Android 内存泄漏分析与解决方法 (2)https://www.cnblogs.com/start1225/p/6903419.html ...

  9. Android内存泄漏分析

    内存泄漏指的是程序中不再使用的对象对象由于某些原因无法被正常GC回收.对象没 有及时释放,就会占据宝贵的内存空间,因而导致后续分配内存的时候,内存空间不足出现OOM.如果无用对象占据的控件越大,那么可 ...

最新文章

  1. 2022-2028年中国氢化丁腈橡胶行业市场深度分析及投资规模预测报告
  2. java关于异常的面试程序题_java异常相关面试题
  3. 快速了解一门技术的基本步骤
  4. WebRTC安全体系架构的8个组件
  5. 如何在网络中成对使用光纤收发器?
  6. python回车键绑定按钮_python tkinter 绑定回车键
  7. SpringCloud与Feign
  8. 用CPU计时器统计CUDA核函数的运行时间
  9. 连接显示器与计算机主机的接口电路是,液晶显示器VGA模拟输入接口电路
  10. scala的静态属性和静态方法
  11. junit测试mysql_使用Junit单元测试及操作MySQL数据库时出现错误及解决方法
  12. matlab半波整流怎么做,基于Matlab的单相半波可控整流电路的设计与仿真.doc
  13. PowerBuilder2017
  14. 微信小程序客服可以直接在手机回复吗,小程序客服功能怎么用手机回复,微信小程序客服手机版
  15. 总结在CentOS7上搭建CUDA10+cudnn7的Tensorflow-gpu环境的经验
  16. TestCenter测试管理工具环境配置(C)
  17. 积木式移动互联网App Hybrid框架-modular的使用(1)
  18. 查询包含关系的SQL
  19. 与 TensorFlow 的初次相遇
  20. 计算机输入法在桌面显示不出来的,电脑桌面输入法不见了怎么办?

热门文章

  1. 【Java 泛型】泛型用法 ( 泛型类用法 | 泛型方法用法 | 泛型通配符 ? | 泛型安全检查 )
  2. 【FFmpeg】使用 FFmpeg 处理音视频格式转换流程 ( 解复用 | 解码 | 帧处理 | 编码 | 复用 )
  3. 【Android 组件化】使用 Gradle 实现组件化 ( 组件模式与集成模式切换 )
  4. 【Android 应用开发】 自定义 圆形进度条 组件
  5. AsyncTask应用解析
  6. springboot-整合freemarker
  7. 如何使用HTML5,CSS3和PHP创建一个联系表格
  8. CSS类命名的语义化VS结构化方式
  9. ymcms SQL注入漏洞
  10. C语言怎么保留n位小数并且四舍五入(附带两种简单方法)