曾让C++程序“羡慕”的JAVA垃圾回收机制是怎么设计的呢?我们先看下面几种垃圾回收机制的做法吧!
引用计数法
对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1,当引用失效时,引用计数器就减1.只要对象A的应用计数器的值为0,则对象A就不可能再被使用
缺点
如果对象A引用了对象B,对象B引用了对象A,而对象A、B都没有被其他对象引用,则A、B应该被回收,这个称谓循环引用,但是引用计数器却不能解决这个问题,从而会导致内存泄漏
标记-清除算法
标记-清除算法分为2个阶段,标记阶段和清除阶段。首先通过根节点,标记所有从根节点开始的可达对象。然后清除所有未被标记的对象。
缺点
回收后的空间是不连续的。在对象的堆空间分配过程中,尤其是大对象的内存分配,不连续的内存空间的工作效率要低于连续的空间。
复制算法
复制算法是一种高效的回收方法。核心思想是:将原有的内存空间分为2块,每次只使用1块。当垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存中,之后,清除正在使用的内存块中的所有对象,交换内存角色,完成内存回收,这个是不是让你想到了新生代的S0、S1区,哈哈,没错,就是用的这个算法……
适用
这个算法适用于存活对象比较少,而垃圾比较多的情况,比如新生代
缺点
这个缺点一眼就能看出,太费内存了
标记-压缩算法
这个是标记-清除算法基础上的改进,他在清除垃圾的同时,还将存活的对象压缩到内存的一段
适用
这个算法适用于存活对象比较多,而垃圾比较少的情况
增量算法
如果一次性将所有的垃圾进行处理,需要造成系统的长时间的停顿,那么就可以让垃圾收集线程和应用程序线程交替执行 。每次,垃圾收集线程只收集一小片区域的内存空间,接着切换到应用程序线程。
缺点
由于线程切换和上下文转换的消耗,会使得垃圾回收的总体成本上升,造成系统吞吐量的下降。
分代
根据上面不同算法的优缺点,让不同的算法服务不同的JVM区域,比如:
- 年轻代中,大约90%的新建对象会很快被回收,因此,年轻代就选择复制算法
- 老年代中,极端情况下,存活率可以达到100%,所以,老年代就选择标记-压缩算法
所以根据应用特点,合理的利用回收算法就是分代的思想