理论教育 内存泄漏的原因及解决方法

内存泄漏的原因及解决方法

时间:2023-06-19 理论教育 版权反馈
【摘要】:什么样的对象GC才会回收呢?名词GC Roots正是分析这一过程的起点,例如JVM自己确保了对象的可到达性,所以GC Roots就是这样在内存中保持对象可到达性的,一旦不可到达,即被回收。所以GC Roots是分析对象为何还存活于内存中的利器。通过java.lang.ref.WeakReference和java.util.WeakHashMap类实现。Phantom Ref(虚引用):根本不会在内存中保持任何对象,只能使用Phantom Ref本身。

内存泄漏的原因及解决方法

JVM会根据generation(代)来进行垃圾回收(Garbage Collection,GC),根据下图4-9所示,一共被分为young generation(年轻代)、tenured generation(老年代)、permanent generation(永久代,perm gen),perm gen(或称Non-Heap非堆)是个异类。注意,heap空间不包括perm gen。

978-7-111-51616-3-Part02-163.jpg

图4-9 JVM根据generation(代)来进行GC

绝大多数的对象都在young generation中被分配,也在young generation中被收回。当young generation的空间被填满时,GC会进行minor collection(次回收),次回收不涉及到heap中的其他generation。minor collection会根据weak generational hypothesis(弱年代假设)来假设young generation中的大量的对象都是垃圾需要回收,minor collection的过程会非常快。在young generation中,没有被回收的对象被转移到tenured generation,然而tenured generation也会被填满,最终触发major collection(主回收),这次回收针对整个heap,由于涉及到大量对象,所以比minor collection慢得多。

什么样的对象GC才会回收呢?当然是GC发现通过任何reference chain(引用链)都无法访问某个对象的时候,该对象即被回收。名词GC Roots正是分析这一过程的起点,例如JVM自己确保了对象的可到达性(那么JVM就是GC Roots),所以GC Roots就是这样在内存中保持对象可到达性的,一旦不可到达,即被回收。通常GC Roots是一个在current thread(当前线程)的call stack(调用栈)上的对象(例如方法参数和局部变量),或者是线程自身或者是system class loader(系统类加载器)加载的类以及native code(本地代码)保留的活动对象。所以GC Roots是分析对象为何还存活于内存中的利器。

从最强到最弱,不同的引用(可到达性)级别反映了对象的生命周期。(www.daowen.com)

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实现。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈