Memory leak troubleshooting MAT tool use

Say before:

Although the Java virtual machine can help us reclaim memory, it reclaims objects that are no longer referenced by the Java virtual machine.

Many times we use the IO stream of the system. If the Cursor and Receiver are not released in time, it will lead to memory leaks. These scenarios are common and can be avoided by general developers.

However, many times the phenomenon of memory leaks is not very obvious.

1. For example, internal classes, memory leaks caused by the use of Handlers,

2. Or you use some references from the third-party library, which consume more resources, but do not cause you to pay enough attention to release them manually like system resources.

When the code is more and more, if the structure is not very clear, even common resources may be omitted, resulting in memory leaks.

Memory leaks are likely to cause memory overflow , which is often referred to as OOM, resulting in application crashes and a bad experience for users.

Finally, it demonstrates how to use MAT in practical applications through memory leak analysis, set usage rate, Hash performance analysis, and OQL fast reading to locate empty sets. (Through some static detection, some memory leak problems can also be found during the development period, and there will be some static detection articles later)

There are generally two reasons for OutOfMemoryError:

1. Memory leaks, the object is dead, and cannot be automatically recycled by the garbage collector. By finding out the location and cause of the leaked code, the solution can be determined;

2. Memory overflow, the objects in the memory must still survive, which means that the Java heap allocation space is insufficient, check the heap setting size (-Xmx and -Xms), and check whether the code has an object whose life cycle is too long and the holding time is too long. long case.

#1 related concepts 

How does the Java virtual machine determine memory leaks? Here are some related concepts


The reference rules in Java are also explained here: from strongest to weakest, different reference (reachability) levels reflect the lifetime of an object.
* Strong Ref (strong reference) : Usually the code we write is Strong Ref, which corresponds to strong reachability. Only when the strong reachability is removed, the object will be recycled.
* Soft Ref (soft reference) : Corresponding to soft reachability, as long as there is enough memory, the object will be kept until it is found that the memory is tight and there is no Strong Ref. Generally used to implement caching,
Implemented            through the java.lang.ref.SoftReference class.
* Weak Ref (weak reference) : weaker than Soft Ref, when it is found that there is no Strong Ref, the object is reclaimed immediately without having to wait until the memory is tight.
           Implemented by java.lang.ref.WeakReference and java.util.WeakHashMap classes .
* Phantom Ref (virtual reference) : No object is kept in memory at all, you can only use the Phantom Ref itself.
        It is generally used to perform a special cleanup process after entering the finalize() method, which is implemented by java.lang.ref.PhantomReference .



##1.1 GC Root ##
The JAVA virtual machine judges whether the object is alive or not through the reachability (Reachability). The basic idea is to search downward with the object of "GC Roots" as the starting point. If an object does not have any reference chain connected to GC Roots (that is, unreachable), the object is determined to be an object that can be recycled, otherwise it cannot be recycled.

GC Roots can be any of the following objects

  • 一个在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之后所能回收到内存的



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

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

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325563277&siteId=291194637