java垃圾回收器需要解决的主要问题:
- 哪些对象需要回收?
- 何时回收这些对象?
- 如何回收这些对象?
1:引用计数法
引用计数法是最古老的算法,对于一个对象A,只要有一个对象引用A,引用计数器就加1,当引用失效时则减1。只要引用计数器的值为0,则对象A就不可能再被使用。
实现方法:
为每个对象配置一个整型的计数器即可。
但这个实现存在一个问题,即无法处理循环引用的情况。因此,java回收机制没有采用这种算法。
2:标记-清除算法
标记-清除算法分为两个阶段:标记阶段和清除阶段。
标记阶段:根据根节点,标记所有从根节点开始的可达对象。因此未标记的对象就是未引用的垃圾对象。
清除阶段:清除所有未标记的对象。
但这个算法会产生大量的空间碎片,这样在对象的分配过程中,尤其是大对象,不连续的内存空间的工作效率要低于连续的空间。
3:复制算法
复制算法:将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将使用的内存中的存活对象复制到未使用的内存块,之后清除正在使用的内存块中所有的对象,交换两个内存的角色,完成垃圾回收。
- 优点:消除碎片
- 缺点:将内存减半
应用:
现在java的新生代串行垃圾回收器使用这个算法。
4:标记-压缩算法
复制算法的高效是建立在存活对象少、垃圾对象多的情况,但老年代最常见的是大部分存活对象。
该算法也是从根节点开始,对所有可达对象做一次标记。然后将存活的对象压缩到内存的一端,之后清理边界所有的空间。这种算法即避免了内存碎片,同时有不需要两块内存。
5:增量算法
大部分垃圾回收算法,是程序出现Stop the world现象,在这种状态下,程序的线程都将挂起,如果垃圾回收时间过长,将严重影响程序效率。
增量算法是的核心是垃圾回收线程和应用程序线程交替执行。即每次垃圾回收器线程只收集一小片区域的内存空间,接着切换到应用线程。
这种算法的缺点是:上下文切换消耗,会是垃圾回收器的总体成本上升,造成系统吞吐量的下降。
6:分代
分代算法是将内存区间根据对象的特点分为几块,根据每块内存区间的特点,使用不同的回收算法,以提高垃圾回收的效率。
以Hot Spot 虚拟机为例,它将所有的新建对象都放入年轻代的内存区域,因此年轻代使用复制算法。当一个对象经过几次回收依然存活,则将对象放入老年代。但老年代中对象的生命周期较长,使用标记压缩算法,以提高垃圾回收效率。