垃圾回收算法

对象是否已死检测策略

垃圾回收时需要判断什么样的对象才是已死的呢,主要有两种方法,引用计数法和可达性分析算法。

引用计数算法

给对象添加一个引用计数器,每当一个对象被引用时,计数器加1;当引用失效时,计数器就减1;任何时刻计数器为0的对象就是不可能再被使用的。客观而言引用计数法实现简单效率也高,在大部分情况下它都是一个不错的算法。但是主流的JVM里没有选用引用计数法来管理内存,其很难解决循环引用的问题

可达性分析算法

通过一些列GC Roots 的对象作为起始点,从这些节点开始向下搜索,搜索所有走过的引用链,当一个对象到GC Roots没有任何引用链相连时,则对象是不可引用的,则可以判定为可回收对象。

GC Roots的对象包括下面几种:

虚拟机栈中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中JNI(即一般说的native方法)引用的对象。

再谈引用

强引用:类似 “Object obj = new Object()” 这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉呗引用的对象

软引用:用来描述一些还有用但并非必须的对象。对于软引用在系统要发生内存溢出之前,将会对这类对象进行第二次回收,如果回收后仍然内存不够,才会抛出内存溢出异常。在JDK1.2之后,提供了SoftReference类来实现软引用。

弱引用:用来描述非必须的对象,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK1.2之后,提供了WeakReference类来实现弱引用。

虚引用:虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不对其生存时间构成影响,也无法通过徐引用来取得一个对象实例。对一个对象设置虚引用的唯一目的就是能在这个对象收集器回收时收到一个系统通知。在JDK1.2之后,提供PhantomReference。

垃圾收集算法

标记清除算法

该算法分为两个阶段:”标记”和”清除”两个过程。其不足主要有两个问题:1)效率问题,标记和清除两个过程的效率都不高。2)标记清除之后会产生大量不连续的内存碎片

复制算法

他将可用的区域按照容量发呢为大小相等的两块,每次只使用其中一块。当这块的内存用完了,就将还存活的对象复制到另外一块上面,然后再把使用过得内存空间清理一次。这样每次都是对半区进行内存回收。内存也不用考虑内存碎片等复杂情况只要已动工堆顶指针按照顺序分配即可。优点:实现简单,运行高效,缺点:空间换时间

标记整理算法

同样分为两个过程:标记整理 标记过程同标记清楚算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉边界以外的内存。

分代收集算法

新生代朝生夕死就采用复制算法,只需要付出很少存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高,没有额外空间对他进行担保就必须使用标记清除或者标记整理算法来进行空间回收。