JAVA垃圾回收主要有以下5种算法:



1、引用计数法

对于一个对象A,则A的引用计数器加1,当引用失效时,引用计数器减1,只要对象A的引用计数器为0,则对象A就不可能被使用。

缺点:无法处理循环引用情况,比如A中引用B,B中引用A,但系统中没有任何第三个对象引用A、B,则A、B永远不能被回收,从而引起内存泄露,所以这种算法不可取。

2、标记-清除算法

此种算法分为两个阶段,在标记阶段,首先通过根节点,标记所有可达对象,为标记的对象则是需要进行回收的对象,然后在清除阶段,将虽有未被标记的对象清除。

缺点:容易产生空间碎片,因为从根节点开始,可达对象与不可达对象均不能保证是连续的内存空间,所以回收后会产生很多内存碎片。系统给新的对象分配内存时,尤其是大对象分配内存时,不连续的内存空间工作效率要远远低于连续的空间。

3、复制算法

复制算法在标记-清除算法上进行了改进,它将原来的内存空间分成两块A、B,每次只使用其中一块(假设为A),垃圾回收时,将A中存活对象复制到B中(注意:此时B中被占用的内存是连续的),之后清除A中所有的对象,完成垃圾回收。

缺点:当存活的对象较多时,复制算法的效率相对来说就很低,所以此算法一般用于存活对象较少的情况,比如新生代。

4、标记-压缩算法

此算法在复制算法上做了一下优化,它会将所有的存活对象压缩到内存的一端,从而避免了碎片的产生,此种算法适用于存活对象较多的情况,如老年代。

5、增量算法

对已大部分的垃圾回收算法,在垃圾回收过程中,系统将处以“stop the world"的状态,即所有线程都会挂起,严重影响用户的体验。

增量算法的基本思想是,如果一次性将所有垃圾进行回收,需要造成系统较长时间的停顿,那么就可以让垃圾回收线程与应用程序线程交替运行,每次只回收部分垃圾,以此反复,直到所有垃圾回收完毕

缺点:因为线程切换和上下文转换的消耗,是的垃圾回收的总体成本上升,造成系统吞吐量下降。