GC垃圾收集

来源:互联网 发布:淘宝怎么添加收藏链接 编辑:程序博客网 时间:2024/06/07 05:54
一、GC的基本原则:分代收集
①频繁收集新生代 MinorGC。
②较少收集老年代 majorGC。
③基本不动永久代。(major可以收集到)
二、判断对象是否存活,是否可以被收集。
1、引用计数法。
对象引用一次,引用计数+1,引用失效,引用计数-1,引用计数0,就可回收了。
不足:性能问题,计算计数。
循环利用:a.b=new B;b.a= new A.,A、B类之间互相引用,却无外部引用。实际上是可以回收的。
2、可达性分析算法。
根据根节点来标记所有从根节点可达的根节点,未标记便是可回收的。
根节点对象为:①:静态变量引用的对象,②:常量引用的对象,③本地栈引用的对象,④java栈中引用的对象。
不足:会产生大量的内存碎片,
利用率不高。
内存中对象可存在的状态:①、可触及的对象,被引用可到达的对象,②可复活的,无引用不可到达的对象, 未经finalize()判定的对象。
③不可触及的对象,不可到达,经finalize()判定过,不会复活的对象。
三、GC算法(具体清理垃圾的算法)
1、标记-清理(清理方法的基础)
可分为:标记阶段(标记可触到的对象),清理阶段(清除其余对象)

不足:效率较低,须递归、遍历全堆对象,清理时需要定制运行程序。独占资源。
产生内存碎片,内存空间未被整理,JVM维护数组等连续对象是需要另外开销。
2、标记-整理(压缩)
可分为:标记阶段,整理阶段(把可达的对象放入一块区域),清除阶段(清除那块区域之外的对象)
适用:较多存活的对象的区域。如老年代。
优势:解决了内存碎片的问题。
不足:效率不高,在标记-清理基础上还加了整理功能,耗费更多性能。
3、复制算法

EdenSpace 中的内存满了,通过minorGC存入survivor0,survivor0满了,则minorGC,存入survivor1中,survivor0清空,survivor1满了,minorGC,存入survivor0,两者以此类推相互切换,总有一个空间为空,默认切换15次后,存入老年代中。
适用于:存活对象较少的区域,如:新生代。
优势:效率高,整理了空间,解决内存碎片问题。
不足:有一块内存为空,浪费内存。
四、GC收集器
1、串行收集器 使用参数-XX:+UseSerialGC,设置
特点:古老、稳定、效率高、停顿时间长。
新生代 用复制算法,老年代中 用标准-压缩。
2、并行收集器
①ParNew 使用JVM参数设置XX:+UseParNewGC
特点:新生代就是并行回收,而老年代依然是串行回收,也就是并行回收器不会影响老年代。
②Parallel
类似ParNew,但是更加关注JVM的吞吐量!
a、使用JVM参数XX:+UseParallelGC设置使用Parallel并行收集器+ 老年代串行,
b、或者使用XX:+UseParallelOldGC,使用Parallel并行收集器+ 并行老年代。
也就是说,Parallel收集器可以同时让新生代和老年代都并行收集。
3、CMS并发标记清除收集器(CompareMarkSweep)
老年代使用的是标记清除算法,而不是标记压缩算法,也就是说CMS是老年代收集器(新生代使用ParNew),

所谓并发标记清除就是CMS与用户线程一起执行。

标记-清除算法与标记-压缩相比,并发阶段会降低吞吐量,使用参数-XX:+UseConcMarkSweepGC打开

五、小结
内存效率:复制算法>标记清除算法>标记整理算法(此处的效率只是简单的对比时间复杂度,实际情况不一定如此)。
内存整齐度:复制算法=标记整理算法>标记清除算法。
内存利用率:标记整理算法=标记清除算法>复制算法。

Hotspot中用的CMS基于 标记-清除(Mark-Sweep)实现,碎片整理则用的标记-整理(Mark-compact)中的Serial Old 回收 进行补偿。