JVM垃圾收集算法

如何定位一个对象是不是垃圾,如果判断一个对象是否存活,有2种方式判断:

1、引用计数法(Reference Counting):每当有一个地方引用时,计数器就会加1;当引用失效时,计数器减1;任何情况下,计数器为0的对象不在被引用。引用计数法实现起来简单,效率挺高,大部分下是一个不错的算法,但是有个致命的问题,无法解决循环引用的问题。判断两个对象为垃圾,但是两个对象相互引用,会造成内存泄漏。

2、可达性分析算法(Reachability Analysis):可达性分析来判断对象的存活,通常用GC Roots对象作为起点,通常当中GCRoots跟的对象有:

 在MemoryAnalyzerTools(MAT)工具里面明确表明了那么可以当作GC Roots 根对象。

在谈下引用,无论是引用计数法还是可达性分析判断对象的引用是否可达,判断对象的存活都与引用有关系:

1、强引用:指在程序代码中普遍存在的,类似于Object obj = new Object();这类的引用可称之为强引用,只要强引用还在,垃圾回收器永远不会回收掉被引用的对象。

2、软引用:用SoftReference来实现软引用,在系统将要内存溢出之前,将这些对象列为回收范围之中二次回收,如果这次回收之后还是内存不够,才会报内存溢出。

3、弱引用:用WeakReference来实现弱引用,这比软引用更弱一点,在垃圾回收的时候,不轮内存够不够用,都会回收被弱引用关联的对象。

4、虚引用:用PhantomReference来实现虚引用,是最弱的一种引用关系,为一个对象设置虚引用的目前就是为了在垃圾回收的时候,可以做后续的通知动作。(通俗的讲,对象死之前,遗言)

垃圾回收算法:

1、标记-清除(Mark-Sweep):最基本的算法,算法分为标记和清除两部分,首先标记要回收的对象,标记完之后统一回收。两个地方不足,一个是效率问题,标记和清除两个过程的效率都不高,二是空间的问题,清除完之后会产生大量的内存碎片。空间碎片太多,在以后来大对象,需要分配内存空间的时候,无法找到连续的内存而不得不提前再次出发垃圾回收的动作。

 

 

 

 

 

 

 2、复制算法(Copying):它是将内存按照容量划分为大小相等的两份,每次只使用其中的一块,当一块用完了,将存活的对象复制到另一块上面,然后把使用过的内存清除掉,这样就不用考虑内存碎片的问题了,这种代价就是将内存缩小为原来的一般,代价有点高。将内存划分为一块较大的Eden空间和两块相同的Survivor空间,默认采用比例8:1:1,复制的时候,指Eden+Survivor向令一个Survivor进行转移,然后清除被转移Survivor区内存。

 

 

 3、标记-整理算法(Mark-Compact):复制算法在对象存活较高的时候,要进行较高的复制操作,效率会变低。和标记-清除算法一样,但后续的动作不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉边界意外的内存。

 

4、分代收集算法(Generational Collection):这中算法并没有什么新的思想,一般java把堆分为年轻代和老年代,这样就可以根据各个年代采用不同的垃圾算法。新生代每次回收的时候发现大批量的对象被回收,只有少量存活,那就采用复制算法,只需要付出少量的存活对象的复制成本就可以完成收集,而老年代,对象存活率高,没有额外的空间,就使用标记-整理或者标记-清除算法进行回收。

 

posted @ 2020-04-17 10:40  ltstar丶滔哥  阅读(178)  评论(0)    收藏  举报