常用的垃圾回收算法
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所产生的停顿。
以上是关于常用的垃圾回收算法的主要内容,如果未能解决你的问题,请参考以下文章