常用的垃圾回收算法

Posted 点滴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了常用的垃圾回收算法相关的知识,希望对你有一定的参考价值。

引用计数法

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

实现也很简单,只需要为每个对象配备一个整型的计数器即可。

缺点:
1.无法处理循环引用的情况
2.引用计算器要求在每次引用产生和消除的时候,需要伴随一个加法操作和减法操作,对系统性能有一定影响。

A引用了B,B又引用了A,因此A和B的引用计数器都不为0,但是系统中却 不存在任何第3个对象引用了A和B。
这种情况下,A和B是无法被回收的,因此会引起内存泄漏。

可达对象:指通过根对象进行引用搜索,最终可以达到的对象。
不可达对象:通过根对象进行引用搜索,最终没有被引用到的对象。

标记清除法

标记清除法是现代垃圾回收算法的思想基础。

标记清除算法将垃圾回收分为俩个阶段:
1.标记阶段
2.清除阶段

一种可行的实现是:
在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象。因此,未被标记的对象就是未被引用的垃圾对象。
然后,在清除阶段,清除所有未被标记的对象。

缺点:容易产生空间碎片。

回收后的空间是不连续的,在对象的堆空间分配过程中,尤其是大对象的内存分配,不连续内存空间的工作效率要低于连续的空间。

复制算法

核心思想:将原有的内存空间分为俩块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换俩个内存的角色,完成垃圾回收。

如果系统中的垃圾对象很多,复制算法需要复制的存活对象数量就会相对较少,真正需要垃圾回收的时候,复制算法的效率是很高的。

由于复制到新的内存空间中,因此可确保回收后的内存空间是没有碎片的。而复制后,在新的内存空间也会保持连续。

缺点:
代价是,将系统内存折半。

Java的新生代串行垃圾回收器中,使用了复制算法的思想。新生代为eden,from,to三个部分,from/to用于存放未被回收的对象。

在垃圾回收时,eden空间中的存活对象会被复制到未使用的survivor空间中(假设是to),正在使用的survivor空间(假设是from)中的年轻对象也会被复制到to空间,大对象或者老年对象直接进入老年代,如果to已满,则对象也会直接进入老年代。
此时,eden和from区的剩余对象就是垃圾对象,可以直接清空。

这种改进的复制算法,既保证了空间的连续性,又避免了大量的内存空间的浪费。

复制算法比较适用于新生代。

标记压缩算法

标记压缩算法是一种老年代的回收算法。它是在标记清除算法的基础上进行了一些优化。

在标记存活对象后,将其压缩到内存的一端,之后清理边界外的所有空间。

1.避免了碎片的产生
2.不需要俩块内存空间

性价比比较高。

等同于标记清除算法执行完成后,再进行一次内存碎片整理。

分代算法

将内存区间根据对象的特点分成几块,根据每块内存空间的特点,适用不同的回收算法,以提高回收的效率。

新生代:复制算法
老年代:标记压缩算法或标记清除算法

分区算法

将整个堆空间划分为连续的不同小区间,每一个小区间都独立使用,独立回收。

好处是可以控制一次回收多少个小区间。

一般来说,在相同条件下,堆空间越大,一次GC时所需的时间就越长,从而产生的停顿也越长,因此根据目标的停顿时间,每次合理地回收若干个小区间,而不是整个堆空间,从而减少一次GC所产生的停顿。

以上是关于常用的垃圾回收算法的主要内容,如果未能解决你的问题,请参考以下文章

垃圾回收算法以及垃圾回收器

java垃圾是怎么回收的,回收算法

垃圾回收算法

垃圾回收算法

垃圾回收算法

垃圾回收算法