目录
一、基础概念
并发收集:指用户线程与垃圾回收线程同时执行(但不一定是并行的,可能会交替执行),用户程序在继续运行,而垃圾收集程序线程运行于另一个CPU上 。
并行收集:指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
吞吐量: 即 CPU 用于运行用户代码的时间与 CPU 总消耗时间的比值。
垃圾收集器:是垃圾回收算法(标记-清除算法、复制算法、标记-整理算法)的具体实现,不同商家、不同版本的JVM所提供的垃圾收集器可能会有很在差别。
二、垃圾收集器
图中展示了7种不同分代的收集器,根据所处区域不同,分为:
新生代收集器:Serial、ParNew、Parallel Scavenge
老年代收集器:CMS、Serial Old、Parallel Old
整堆收集器:G1
两个收集器间有连线,表明它们可以搭配使用
1. Serial收集器
Serial(串行)垃圾收集器是最基本、发展历史最悠久的收集器。
1. 特点:
针对新生代;
采用复制算法;
单线程收集;
进行垃圾收集时,必须暂停所有工作线程,直到完成,即会STW ("Stop The World")。
2. 适用场景:Client模式下的虚拟机。
Serial/Serial Old组合收集器运行示意图如下:
2. ParNew收集器
ParNew垃圾收集器是Serial收集器的多线程版本,其余行为和 Serial 收集器一模一样。
1. 特点:
针对新生代;
多线程;
同Serial收集器可用控制参数、收集算法、Stop The World、内存分配规则、回收策略等;
ParNew垃圾收集器默认开启的收集线程是 CPU 的核数。
2. 适用场景:ParNew垃圾收集器还许多运行在server模式下的虚拟机中首选的新生代垃圾收集器,因为它是除Serial收集器唯一一个能与CMS收集器配合工作的。
ParNew/Serial Old组合收集器运行示意图如下:
3. Parallel Scavenge收集器
Parallel Scavenge垃圾收集器因为与吞吐量关系密切,也称为吞吐量收集器(Throughput Collector)。
1. 特点:
针对新生代;
采用复制算法;
多线程收集。
值得注意的是,GC自适应调节策略(与ParNew垃圾收集器重要区别)开启这个参数后 "-XX:+UseAdptiveSizePolicy",就不用手工指定一些细节参数,如:新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRation)、晋升老年代的对象年龄(-XX:PretenureSizeThreshold)等;JVM会根据当前系统运行情况收集性能监控信息,动态调整这些参数,以提供最合适的停顿时间或最大的吞吐量,这种调节方式称为GC自适应的调节策略(GC Ergonomiscs);
2.适用场景:那些执行批量处理、订单处理、工资支付、科学计算的应用程序。
4. Serial Old收集器
Serial Old是 Serial收集器的老年代版本。
1、特点:
针对老年代;
采用"标记-整理"算法(还有压缩,Mark-Sweep-Compact);
单线程收集。
2、适用场景:Client模式下的虚拟机;也可在server模式下使用,主要有两大用途:
(A)在JDK1.5及之前,与Parallel Scavenge收集器搭配使用(JDK1.6有Parallel Old收集器可搭配);
(B)作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用;
Serial/Serial Old收集器运行示意图如下:
5. Parallel Old收集器
Parallel 是 Parallel Scavenge垃圾收集器老年代版本。
1、特点:
针对老年代;
采用"标记-整理"算法;
多线程收集。
2、适用场景:注重吞吐量以及CPU资源敏感的场景,就优先考虑Parallel Scavenge加Parallel Old收集器。
Parallel Scavenge/Parallel Old收集器运行示意图如下:
6. CMS收集器
并发标记清理(Concurrent Mark Sweep,CMS)收集器也称为并发低停顿收集器(Concurrent Low Pause Collector)或低延迟(low-latency)垃圾收集器,是一种以获取最短停顿时间为目标的收集器。
1、特点:
针对老年代;
基于"标记-清除"算法(不进行压缩操作,产生内存碎片);
并发收集、低停顿;
需要更多的内存。
2、适用场景:与用户交互较多的场景。
3、CMS收集器运作过程:
a. 初始标记(CMS initial mark):仅标记一下GC Roots能直接关联的对象,速度很快, 需要"Stop The World"。
b. 并发标记(CMS concurrent mark):进行 GC Roots Tracing 的过程,刚才产生的集合中标记出存活对象。应用程序也在运行,并不能保证可以标记出所有的存活对象。
c. 重新标记(CMS remark):为了修正并发标记期间因用户程序继续运作而导致标记变动的那一部分对象的标记记录,需要"Stop The World",且停顿时间比初始标记稍长,但远比并发标记短,采用多线程并行执行来提升效率。
d. 并发清除(CMS concurrent sweep):回收所有的垃圾对象;
整个过程中耗时最长的并发标记和并发清除都可以与用户线程一起工作。
所以总体上说,CMS收集器的内存回收过程与用户线程一起并发执行;
CMS收集器运行示意图如下:
4. 缺点:
1> 对CPU资源非常敏感;
2> 无法处理浮动垃圾,可能出现"Concurrent Mode Failure"失败;
浮动垃圾(Floating Garbage) :在并发清除时,用户线程新产生的垃圾,称为浮动垃圾;
3> 产生大量内存碎片。
7. G1收集器
G1(Garbage-First)是JDK7-u4才推出商用的收集器。
1、特点:
并行与并发:能充分利用多CPU、多核环境下的硬件优势,通过并行来缩短"Stop The World"停顿时间,也可以并发让垃圾收集与用户程序同时进行;
分代收集,收集范围包括新生代和老年代 :能独立管理整个GC堆(新生代和老年代),而不需要与其他收集器搭配,能够采用不同方式处理不同时期的对象。虽然保留分代概念,但Java堆的内存布局有很大差别,将整个堆划分为多个大小相等的独立区域(Region),新生代和老年代不再是物理隔离,它们都是一部分Region(不需要连续)的集合。
结合多种垃圾收集算法,空间整合,不产生碎片:从整体看,是基于标记-整理算法,从局部(两个Region间)看,是基于复制算法,都不会产生内存碎片,有利于长时间运行。
可预测的停顿:低停顿的同时实现高吞吐量,G1除了追求低停顿处,还能建立可预测的停顿时间模型, 可以明确指定M毫秒时间片内,垃圾收集消耗的时间不超过N毫秒。
2、适用场景:面向服务端应用,针对具有大内存、多处理器的机器;最主要的应用是为需要低GC延迟,并具有大堆的应用程序提供解决方案;
如:在堆大小约6GB或更大时,可预测的暂停时间可以低于0.5秒
3. 为什么G1收集器可以实现可预测的停顿
可以有计划地避免在Java堆的进行全区域的垃圾收集。
G1跟踪各个Region获得其收集价值大小,在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region(名称Garbage-First的由来),这就保证了在有限的时间内可以获取尽可能高的收集效率。
4. 一个对象被不同区域引用的问题
一个Region不可能是孤立的,一个Region中的对象可能被其他任意Region中对象引用,判断对象存活时,是否需要扫描整个Java堆才能保证准确?
- 无论G1还是其他分代收集器,JVM都是使用Remembered Set来避免全局扫描。
- 每个Region都有一个对应的Remembered Set。
- 每次Reference类型数据写操作时,都会检查将要写入的引用指向的对象是否和该Reference类型数据在不同的Region。
- 如果不同,就把相关引用信息记录到引用指向对象的所在Region对应的Remembered Set中。
- 当进行垃圾收集时,在GC根节点的枚举范围加入Remembered Set,就可以保证不进行全局扫描,也不会有遗漏。
5. G1收集器运作过程
不计算维护Remembered Set的操作,可以分为4个步骤(与CMS较为相似)。
(A)初始标记(Initial Marking)
仅标记一下GC Roots能直接关联到的对象,且修改TAMS(Next Top at Mark Start),让下一阶段并发运行时,用户程序能在正确可用的Region中创建新对象,需要"Stop The World",但速度很快。
(B)并发标记(Concurrent Marking)
进行GC Roots Tracing的过程,刚才产生的集合中标记出存活对象,耗时较长,但应用程序也在运行,并不能保证可以标记出所有的存活对象。
(C)最终标记(Final Marking)
为了修正并发标记期间因用户程序继续运作而导致标记变动的那一部分对象的标记记录,上一阶段对象的变化记录在线程的Remembered Set Log,这里把Remembered Set Log合并到Remembered Set中,需要"Stop The World",且停顿时间比初始标记稍长,但远比并发标记短, 采用多线程并行执行来提升效率;
(D)筛选回收(Live Data Counting and Evacuation)
首先排序各个Region的回收价值和成本,然后根据用户期望的GC停顿时间来制定回收计划,最后按计划回收一些价值高的Region中垃圾对象。回收时采用"复制"算法,从一个或多个Region复制存活对象到堆上的另一个空的Region,并且在此过程中压缩和释放内存,可以并发进行,降低停顿时间,并增加吞吐量。
G1收集器运行示意图如下: