垃圾收集算法常用的有哪几种?都有什么机制?

TheDisguiser 2020-05-05 21:20:57 java常见问答 5328

在java开发中,有时候会因为各种原因而使程序中产生各种的的垃圾,这时候就需要垃圾收集算法出场了,下面我们就来看看常用的几种垃圾收集算法吧。

一、标记—清除算法

标记—清除算法是最基础的收集算法,过程分为标记和清除两个阶段,首先标记出需要回收的对象,再由虚拟机统一回收已标记的对象。这种算法的不足主要有两个:

1、效率:它的标记、清除的效率都不高;

2、空间:对象被回收之后会产生大量不连续的内存碎片,当需要分配较大对象时,由于找不到合适的空闲内存而不得不再次触发垃圾回收动作。

二、复制算法(一般用于回收新生代)

为了解决效率问题,复制算法出现了。算法的基本思路是:将内存划分为大小相等的两部分,每次只使用其中一半,当第一块内存用完了,就把存活的对象复制到另一块内存上,然后清除剩余可回收的对象,这样就解决了内存碎片问题。我们只需要移动堆顶指针,按顺序分配内存即可,简单高效。但是它的缺点也很明显:

1、它会浪费一半的内存,这是很难接受的一点。

2、假如对象的存活率比较高,我们可以偏激一点,假设是100%存活,那么我们就要把全部对象都复制一遍,并且把引用地址全部重置一遍。这样花费的时间,在对象存活率达到一定程度时,就会变的不可忽视。

我们可以看到,想要使用复制算法,需要对象的存活率非常之低,最最重要的是,我们必须要克服整整百分之五十内存的浪费。

三、标记—整理算法(一般用于老年代回收)

根据老年代的特点,有人提出了另一种改进后的“标记—清除”算法:标记—整理算法。

标记:它的第一个阶段与标记/清除算法是一模一样的,均是遍历GC Roots,然后将存活的对象标记。

整理:移动所有存活的对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收。因此,第二阶段才称为整理阶段。

我们看到,标记的存活对象会被整理出来,分别按照内存地址依次排序,那些未被标记的内存则会被清理掉。这样,当我们需要给新对象分配内存时,JVM虚拟机就只需要持有一个内存的起始地址即可,这样就少了许多内存的不必要消耗。

可以看出,标记/整理算法不仅可以弥补标记/清除算法当中,内存区域比较分散的缺点,也一并消除了内存减半的不必要浪费,可以说是事半功倍。

四、分代收集算法

现代商业虚拟机垃圾收集大多采用分代收集算法。主要思路是根据对象存活生命周期的不同将内存划分为几块。一般是把Java堆分为新生代和老年代,然后根据各个年代的特点采用最合适的收集算法。新生代中,对象的存活率比较低,所以选用复制算法,老年代中对象存活率高且没有额外空间对它进行分配担保,所以使用“标记-清除”或“标记-整理”算法进行回收。

这就是一些常用的垃圾收集算法使用了,更多java架构师详情请持续关注我们了解消息吧。