JVM 垃圾回收算法
来自: http://my.oschina.net/u/1041012/blog/616142
对象可触及性算法
可触及性算法是判断对象是否死亡的最基本的算法。所谓死亡对象就是内存堆中不再使用的对象。
用于被GC回收的对象。
引用计数算法 Reference Counting
引用计数法是给对象中添加一个引用计数器,每当有一个地方引用它时,计数器加1,
当引用失效时,计数器减1;任何时候计算器都为0的对象就是不可触及的对象。Reference Counting 判定效率高,实现简单。
微软的COM,ActionScript3,FlashPlayer3,Python 都采用Reference Counting来计算Java 语言中没有采用这个算法的主要原因是,它难以解决循环引用的问题。
根搜索算法 GC Root Tracing
基本思路就是就是通过一系列名为 GC Root 的对象作为起始点,从这些节点开始向下搜索,
搜索走过的路劲作为引用链,当一个对象到GC Root 没有任何引用链时,则证明此对象不可触及
GC Root 包括以下几种
虚拟机栈中的引用的对象
方法区中的类静态属性引用的对象
方法区中的常量引用的对象
本地方法栈中JNI的引用的对象。
垃圾回收算法
标记-清楚算法 Mark-Sweep
标记-清楚算法是最基本的算法,其算法分为两个阶段,标记阶段和清除阶段。
首先标记出所需要回收的对象,标记完成后统一收掉所有的被标记的对象。
他的缺点主要有两个:
效率问题,标记和清除的效率都不高
空间问题,标记清除后会产生大量的碎片内存
复制算法 Copying
为了解决效率问题,复制算法将可用内存分为大小相等的两块,每次只用其中一块。
当一块内存用完了,就将还存活着的对象复制到另外一块上面,然后把已用过的内存空间一次清理掉。内存分配不用考虑碎片等复杂情况,只要移动堆顶指针,实现简单,运行高效。只是这种算法的代价是将内存缩小为原来的一半。
**
在实际应用中,不会简单的把所有存活对象从一边拷贝到另外一边,经过优化,会把大对象放到老生代的内存区域中,这一动作其实就是内存分配担保的一个动作(Handle Promotion)。
我们没有办法保证每次需要复制的内存对象 在另一块区域一定够,这时需要借一块区域通常来说是老年代存放,在清理之后在放回去,或者说就长期放在老年代了。
**
标记-压缩算法 Mark-Compact
标记-压缩算法是 标记-清除算法的一种优化,标记过程仍然一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
分代收集 General Collection
所谓分代收集其实是各种回收算法的综合应用。根据对象的存活周期的不同将内存划分为几块。一般是把Java堆分为新生代和老年代。
新生代中,每次垃圾收集时都要发现大批对象死去,只有少量存活,那就选用复制算法,只需付出少量存活对象的复制。
而老年代中因为对象的存活率高,没有额外的空间对它进行分配担保,就必须使用标记清理或者压缩算法。