垃圾回收器介绍
没有最好的垃圾回收器,没有万能的回收器,我们只是在对应的应用选择合适的垃圾收集器。
注意区分并发和并行
并发concurrent:用户线程和垃圾收集线程同时工作。
并行parallel:多个垃圾收集线程同时工作,用户线程仍然在等待
一、Serial收集器
在jdk1.3之前,是虚拟机新生代收集的唯一选择。这是一个单线程的收集器,只使用一个收集线程完成收集工作,在进行垃圾回收时,必须暂停其他所有的工作线程(stop the world),直到收集结束。就像打扫房间一样,在打扫的同时,不能乱扔纸屑,否则,何年何月能打扫干净?
目前仍是虚拟机运行在client模式下的默认的新生代收集器。相比较其他单线程收集器而言,简单高效。
二、ParNew收集器
ParNew收集器是serial收集器的多线程版本。除了使用多线程外,其余行为包括serial收集器可用的所有控制参数,收集算法,stop the world、对象分配规则,回收策略都一模一样。
目前仍是虚拟机运行在server模式下的虚拟机首选的新生代收集器。也是唯一的可以与CMS收集器配合工作。
在单线程的环境下,效果不会比serial好。
三、Parallel Scavenge收集器
是一个新生代收集器,使用复制算法。是并行的多线程收集器,也称吞吐量优先收集器。
Parallel Scavenge收集器的关注点和其他收集器不同,其他收集器的关注点是如何尽量缩短垃圾收集时用户线程的等待时间。而Parallel Scavenge收集器的目标是达到一个可控制的吞吐量(Throughput),所谓的吞吐量就是cpu用于运行用户代码的时间和cpu总消耗的时间的比值。
吞吐量 = 运行用户代码时间 / (运行用户代码时间+垃圾回收时间),比如虚拟机总共运行 100 minutes,垃圾回收花掉1 minute,那么吞吐量就是99 / 100 = 99%.
也就是说吞吐量越高,那么停顿时间越短,高效的利用cpu。
Parallel Scavenge收集器提供两个参数用于精确控制吞吐量。
GC的停顿时间是以牺牲吞吐量和新生代空间换取的。
- -XX:GCTimeRatio设置吞吐量
- -XX:MaxGCPauseMillis 控制最大停顿时间
四、Serial Old收集器
是serial收集器的老年代版本。也是单线程,使用标记-整理算法。主要意义是给Client模式下的虚拟机使用。
在server模式下,也有两个用途
- 1、在jdk 1.5及以前的版本中与parallel scavenge收集器配合使用
- 2、作为cms收集器的后备预案,在并发收集发生Concurent mode failure时使用。
五、Parallel Old收集器
是parallel scavenge的老年代版本。使用多线程和标记-整理算法。这个收集器在jdk1.6中提供。
六、CMS收集器 Concurrent Mark Sweep
是优秀的收集器,并发收集,低停顿。以获取最短回收停顿时间为目标的收集器。采用标记-清除算法。
运作相对比较复杂,过程有四个步骤
1、初始标记 (CMS initial mark) 需要stop the world
仅仅是标记一下GC Roots能直接关联到的对象,速度很快。
2、并发标记 (CMS concurrent mark)
进行GC Roots Tracing的过程
3、重新标记 (CMS remark) 需要stop the world
为了修正并发标记阶段期间因用户程序运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长,但远比并发标记的时间短。
4、并发清除 (CMS Concurrent sweep)
CMS收集器存在的问题
1、对cpu资源非常敏感。其实,面向并发设计的程序都对cpu资源敏感,在并发阶段,虽然不会导致用户线程(程序)停顿,但是会因为占用了一部分cpu资源而导致应用程序变慢,总吞吐量会降低。
2、无法处理浮动垃圾
可能出现concurrent mode failure失败而导致另一次full gc的产生。
Floating Garbage : cms收集器在并发清理阶段用户线程还在运行,伴随着垃圾的产生。这部分垃圾称为浮动垃圾
3、内存碎片
采用标记-清理算法实现的。
七、G1收集器 Garbage-First
是当今收集器技术的最前沿成果之一。jdk 1.7,面向服务端应用的垃圾收集器。
运作的阶段:
1、初始标记(initial Marking) 和CMS 相同
2、并发标记(concurrent Marking) 和cms相同
3、最终标记(final Marking)
为了修正并发标记阶段期间因用户程序运作而导致标记产生变动的那一部分对象的标记记录,虚拟机将这这段时间对象变化记录在Remembered set logs里面。然后把Remembered set logs的数据合并到Remembered Set中,这阶段需要停顿线程,但是可并行执行。
4、筛选回收(Live Data Counting and evacuation)
首先对各个region的回收价值和成本进行排序,根据用户所期望的GC 停顿时间来指定回收计划。
和cms的比较
1、并行与并发
G1可以充分的利用多CPU,多核环境下的硬件优势,使用多个cpu或者多核来缩短stop-the-world的停顿时间
2、分代收集
可以独立管理整个GC 堆,不需要其他收集器配合。同样使用分代概念。但他可以采用不同的方式去处理新创建的对象和存活了一段时间的对象。
3、空间整合
整体是基于标记-整理算法,从局部看(两个region之间)使用复制算法
4、可预测的停顿
G1除了追求低停顿之外,还能建立可预测的停顿时间模型,几乎是实时垃圾回收器的特征了。
核心:如何避免遗漏?
G1之前的收集器的收集范围都是整个新生代或者老年代,而G1不再是这样。
G1将整个Java堆划分成许多独立区域Region,虽然保留了新生代和老年代的概念,但是不再是物理隔离了。每个region对应一个remembered Set,虚拟机发现程序在对reference类型的数据进行写操作时,会产生一个write barrier暂时中断写操作,检查reference引用的对象是否处于不同的region之中,如果是,便通过cardTable把相关引用信息记录到被引用对象所属的region的remembered Set之中。当进行内存回收时,在GC 根节点的枚举范围中加入 remembered set之中即可保证不对全堆进行扫描也不会有遗漏。