- 收集算法是内存回收的方法论
- 垃圾收集器就是内存回收的实践者
- 本节介绍JDK 7 Update4 之后 , JDK 11发布之前。 HotSpot虚拟机中所包含的全部可用的垃圾收集器。
3.5.1 Serial收集器
- Serial收集器是最基础、历史最悠久的收集器。
3.5.2 ParNew收集器
- ParNew收集器实质上是Serial收集器的多线程并发版本。
- 除了使用多条线程进行垃圾收集之外,其余的行为包括Serial收集器可用的所有控制参数、收集算法、Stop The World 、对象分配规则、回收策略等都与Serial收集器完全一致。
3.5.3 Parallel Scavenge收集器
- Parallel Scavenge也是一款新生代收集器,它同样是基于标记-复制算法实现的收集器,也是能够并行收集的多线程收集器。
- Parallel Scavenge收集器经常也被称为"吞吐量优先收集器"
- 他还有一个参数 -XX:+UseAdaptiveSizePolicy,这是一个开关参数。 这个参数被激活后,虚拟机会根据当前系统的运行情况收集性能监控信息,动态地调整这些参数以提供最合适的停顿时间或者最大的吞吐量。
- 这种调节方式叫做 垃圾收集的自适应调节策略。
3.5.4 Serial Old收集器
- Serial Old是 Serial收集器的 老年代版本
- 它同样是一个单线程收集器,使用标记-整理算法
3.5.5 Parallel Old收集器
- Parallel Old是Parallel Scavenge收集器的老年代版本。
- 支持多线程并行收集,基于标记-整理算法实现。
3.5.6 CMS收集器
-
CMS收集器是一种以获取最短回收停顿时间为目标的收集器。(Concurrent Mark Sweep)
-
目前很大一部分的Java应用集中在互联网网站或者基于浏览器的B/S系统的服务端上。
-
这类应用通常会很关注服务的响应速度,希望系统停顿时间尽可能短。 CMS收集器就很符合这类应用的需求。
-
耗时最长的并发标记和并发清除过程,垃圾收集器线程都可以和用户线程一起工作。
-
总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。
-
CMS在JDK 9 已经被deprecated
3.5.7 Garbage First收集器
- G1收集器是垃圾收集器技术发展历史上的里程碑式的成果。
- 它开创了收集器 面向局部收集的设计思路和基于Region的内存布局形式。
G1收集器的运作过程
- 大致可以分为下面四个步骤
- 初始标记
- 标记一下GC Roots能直接关联到的对象
- 修改TAMS指针的值,让下一阶段用户线程并发运行时,能正确地在可用的Region中分配新对象。
- 需要停顿线程,但是耗时很短,并且是借用进行Minor GC的时候同步完成。
- 并发标记
- 从GC Roots开始对堆中对象 进行 可达性分析 , 递归扫描整个堆里的对象图。
- 这个阶段耗时较长,可以与用户程序并发执行。
- 扫描完后,重新处理STAB记录下的在并发时有变动的对象。
- 最终标记
- 对用户线程做一个短暂的暂停
- 用于处理并发阶段结束后,仍然遗留下来的最后少量的STAB记录。
- 筛选回收
- 负责更新Region的统计数据,将各个Region的回收价值和成本进行排序
- 根据用户期望的停顿时间制定回收计划。
- 将任意多个Region构成回收集,然后把决定回收的那一部分Region里面的存活对象复制到空的Region,清理掉旧的Region的全部空间。
- 这里操作设计对象的移动,必须暂停用户线程。
相对于CMS的优缺点
- 优点
- 创新性设计:指定最大停顿时间、分Region的内存布局、按受益动态确定回收集
- 算法的优势,整体来看是基于"标记-整理",从局部,两个Region上来看,又是基于"标记-复制"算法实现。 相比于CMS的清理算法,不会产生内存空间碎片
- G1使用写后屏障进行卡表维护操作外,为了实现原始快照搜索(SATB)算法,还需要使用写前屏障来跟踪并发时的指针变化情况。 原始快照搜索 能够减少并发标记和重新标记阶段的消耗
- 缺点
- G1无论是垃圾收集产生的内存占用 还是 程序运行时的额外执行负载 都要比CMS高。
- G1的卡表实现更为复杂,并且每个Region无论代表新生代还是老生代,都会有一份卡表。 导致G1的记忆集占整个堆容量的20%甚至更多。
- G1对写屏障的复杂操作要比CMS消耗更多的运算资源。 CMS的写屏障是同步操作,而G1将写前屏障和写后屏障中要做的事情放入队列,异步处理。