内存泄漏排查 MAT工具使用

説在前面:

尽管Java虚拟机可以帮我们对内存进行回收,但是其回收的是Java虚拟机不再引用的对象。

很多时候我们使用系统的IO流,Cursor,Receiver如果不及时释放,就会导致内存泄漏,这些场景是常见的,一般开发人员也都能够避免。

但是,很多时候内存泄漏的现象不是很明显,

1.比如内部类,Handler相关的使用导致的内存泄漏,

2.或者你使用了第三方library的一些引用,比较消耗资源,但又不是像系统资源那样会引起你足够的注意去手动释放它们。

当代码越来越多,如果结构不是很清晰,即使是常见的资源也有可能略掉,从而导致内存泄漏。

内存泄漏很有可能会导致内存溢出,就是常说的OOM,从而导致应用crash,给用户一种糟糕的体验。

最后通过内存泄漏分析,集合使用率,Hash性能分析,OQL快读定位空集合实战演示如何在实际应用中使用MAT。(通过一些静态检测也可以在开发期发现一些内存泄漏的问题,后面会有一些静态检测的文章)

造成OutOfMemoryError原因一般有2种:

1、内存泄露,对象已经死了,无法通过垃圾收集器进行自动回收,通过找出泄露的代码位置和原因,才好确定解决方案;

2、内存溢出,内存中的对象都还必须存活着,这说明Java堆分配空间不足,检查堆设置大小(-Xmx与-Xms),检查代码是否存在对象生命周期太长、持有状态时间过长的情况。

#一 相关概念 

Java虚拟机如何判定内存泄漏的呢?下面介绍一些相关概念


这里也要说明一下Java的引用规则:从最强到最弱,不同的引用(可到达性)级别反映了对象的生命周期。
* Strong Ref(强引用):通常我们编写的代码都是Strong Ref,于此对应的是强可达性,只有去掉强可达,对象才被回收。
* Soft Ref(软引用):对应软可达性,只要有足够的内存,就一直保持对象,直到发现内存吃紧且没有Strong Ref时才回收对象。一般可用来实现缓存,
           通过java.lang.ref. SoftReference类实现。
* Weak Ref(弱引用):比Soft Ref更弱,当发现不存在Strong Ref时,立刻回收对象而不必等到内存吃紧的时候。
           通过java.lang.ref.WeakReference和java.util. WeakHashMap类实现。
* Phantom Ref(虚引用):根本不会在内存中保持任何对象,你只能使用Phantom Ref本身。
        一般用于在进入finalize()方法后进行特殊的清理过程,通过 java.lang.ref. PhantomReference实现。



##1.1 GC Root ##
JAVA虚拟机通过可达性(Reachability)来判断对象是否存活,基本思想:以”GC Roots”的对象作为起始点向下搜索,搜索形成的路径称为引用链,当一个对象到GC Roots没有任何引用链相连(即不可达的),则该对象被判定为可以被回收的对象,反之不能被回收。

GC Roots可以是以下任意对象

  • 一个在current thread(当前线程)的call stack(调用栈)上的对象(例如方法参数和局部变量)
  • 线程自身或者system class loader(系统类加载器)加载的类
  • native code(本地代码)保留的活动对象

##1.2 内存泄漏
对象无用了,但仍然可达(未释放),垃圾回收器无法回收。

##1.3 强(strong)、软(soft)、弱(weak)、虚(phantom)引用 ##

Strong references

普通的java引用,我们通常new的对象就是:
StringBuffer buffer = new StringBuffer();
如果一个对象通过一串强引用链可达,那么它就不会被垃圾回收。你肯定不希望自己正在使用的引用被垃圾回收器回收吧。但对于集合中的对象,应在不使用的时候移除掉,否则会占用更多的内存,导致内存泄漏。


Soft reference
当对象是Soft reference可达时,gc会向系统申请更多内存,而不是直接回收它,当内存不足的时候才回收它。因此Soft reference适合用于构建一些缓存系统,比如图片缓存。

WeakReference

WeakReference不会强制对象保存在内存中。它拥有比较短暂的生命周期,允许你使用垃圾回收器的能力去权衡一个对象的可达性。在垃圾回收器扫描它所管辖的内存区域过程中,一旦gc发现对象是weakReference可达,就会把它放到ReferenceQueue中,等下次gc时回收它。
WeakReference<Widget> weakWidget = new WeakReference<Widget>(widget);
系统为我们提供了WeakHashMap,和HashMap类似,只是其key使用了weak reference。如果WeakHashMap的某个key被垃圾回收器回收,那么entity也会自动被remove。

由于WeakReference被GC回收的可能性较大,因此,在使用它之前,你需要通过weakObj.get()去判断目的对象引用是否已经被回收.

Reference queque

一旦WeakReference.get()返回null,它指向的对象就会被垃圾回收,那么WeakReference对象就没有用了,意味着你应该进行一些清理。比如在WeakHashMap中要把回收过的key从Map中删除掉,避免无用的的weakReference不断增长。
ReferenceQueue可以让你很容易地跟踪dead references。WeakReference类的构造函数有一个ReferenceQueue参数,当指向的对象被垃圾回收时,会把WeakReference对象放到ReferenceQueue中。这样,遍历ReferenceQueue可以得到所有回收过的WeakReference。

Phantom reference

和soft,weak Reference区别较大,它的get()方法总是返回null。这意味着你只能用PhantomReference本身,而得不到它指向的对象。当WeakReference指向的对象变得弱可达(weakly reachable)时会立即被放到ReferenceQueue中,这在finalization、garbage collection之前发生。理论上,你可以在finalize()方法中使对象“复活”(使一个强引用指向它就行了,gc不会回收它)。但没法复活PhantomReference指向的对象。而PhantomReference是在garbage collection之后被放到ReferenceQueue中的,没法复活。

关于Phantom reference的更多讨论,请参考:understanding-weak-references


Heap dump是java进程在特定时间的一个内存快照。通常在触发heap dump之前会进行一次full gc,这样dump出来的内容就包含的是被gc后的对象。


MAT 不是一个万能工具,它并不能处理所有类型的堆存储文件。但是比较主流的厂家和格式,例如 Sun, HP, SAP 所采用的 HPROF 二进制堆存储文件,以及 IBM 的 PHD 堆存储文件等都能被很好的解析。

工具地址 : https://www.eclipse.org/mat/

1. 用jmap生成堆信息

100252_ot9E_1767531.png

这样在E盘的jmap文件夹里会有一个map.bin的堆信息文件 

2. 将堆信息导入到mat中分析   

101421_bdMx_1767531.png


3. 生成分析报告

    mat可以为我们生成多个报告:

    140753_cUoj_1767531.png    140754_Uq2P_1767531.png

    140755_JHbD_1767531.png    140755_iAe6_1767531.png


    下面来看看生成的这些数据对我们有什么帮助

    114056_IgFu_1767531.png

    从上图可以看到它的大部分功能,在饼图上,你会发现转储的大小和数量的类,对象和类加载器。
正确的下面,饼图给出了一个印象最大的对象转储。移动你的鼠标一片看到对象中的对象的细节检查在左边。下面的Action标签中:

  • Histogram可以列出内存中的对象,对象的个数以及大小。

  • Dominator Tree可以列出那个线程,以及线程下面的那些对象占用的空间。

  • Top consumers通过图形列出最大的object。

  • Leak Suspects通过MA自动分析泄漏的原因。

Histogram

    120039_qSi5_1767531.png

  • Class Name : 类名称,java类名

  • Objects : 类的对象的数量,这个对象被创建了多少个

  • Shallow Heap :一个对象内存的消耗大小,不包含对其他对象的引用

  • Retained Heap :是shallow Heap的总和,也就是该对象被GC之后所能回收到内存的



总结出来只有一条: 存在无效的引用! 

良好的模块设计以及合理使用设计模式有助于解决此问题。

猜你喜欢

转载自blog.csdn.net/lixld/article/details/80212193