并行:多条垃圾收集线程并行工作,用户线程处于等待状态
如:ParNew、Parallel Scavenge、Parallel Old
并发:指用户线程与垃圾线程同时执行(但不一定是并行的,可能会交替执行)
吞吐量就是CPU 运行用户代码的时间 与 CPU总消耗时间 的比值。
吞吐量 = 运行用户代码的时间 / (运行用户代码的时间+垃圾收集的时间)
假设虚拟机总共运行了100分钟,其中垃圾收集花了一分钟 吞吐量就是99%
在正式了解虚拟机之前,我们先看一下JVM包含的收集器(以HotSpot为例)
上图展示了7种作用于不同分代的收集器,如果两个收集器之间存在连接,就说明他们之间可以搭配使用,所处的区域,表示它是属于新生代收集器还是老年代收集器。
Serial收集器是最基本、发展历史最悠久的收集器,在JDK1.3.1之前,是虚拟机新生代收集的唯一选择
这个收集器是一个单线程的收集器,但是它的"单线程"的意义并不仅仅说明它只会使用一个CPU或者一条收集线程去完成垃圾收集工作,更重要的是它进行垃圾收集时,必须暂停其他所有的工作线程,直到收集结束
Serial收集器是虚拟机运行在Client模式下的默认的新生代收集器
Client模式:之前的版本有参数-client,客户端程序可以加-client,但是JDK1.8之后被取消了
java开发桌面程序,虚拟机就分为Client模式和Server模式,Server模式没有必要加载可视化界面,所以就有之前的Client。
简单、高效(与其它收集器的单线程比),对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率
ParNew收集器其实就是Serial收集器的多线程版本,除了使用多条线程进行垃圾收集外,其余与Serial收集器完全一样。
ParNew收集器是许多运行在Server模式下的虚拟机中首选的新生代收集器
与Serial收集器相比,ParNew在单CPU的环境下绝对不会有比Serial收集器更好的效果,甚至由于存在线程交互的开销,该收集器在通过超线程技术实现的两个CPU环境中都不能百分之百的保证可以超过Serial收集器。
然而随着可以使用的CPU的数量的增加,它对于GC时系统资源的有效利用还是很有好处的。
Parallel Scavenge收集器是一个新生代收集器,使用复制算法的并行收集器
Parallel Scavenge 收集器使用两个参数控制吞吐量
MaxGCPauseMillis:控制最大的垃圾收集停顿时间
GCRatio:直接设置吞吐量的大小
直观上,只要最大的垃圾收集停顿时间越小,吞吐量是越高的,但是GC停顿时间的缩短是以牺牲吞吐量和新生代空间作为代价的。比如原来10秒收集一次,每次停顿100毫秒。但是线程编程每5秒收集一次,每次停顿70毫秒,停顿时间下降的同时,吞吐量也下降了。
停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验,而高吞吐量则可以高效地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。
Parallel Scavenge收集器与ParNew收集器的一个重要区别是它具有自适应调节策略
Parallel Scavenge收集器有一个参数- XX:+UseAdaptiveSizePolicy
当这个参数打开之后,就不需要手动指定新生代的大小,Eden和Survivor区的比例,晋升老年代对象等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大吞吐量,这种调节方式成为GC自适应的调节策略。
由于垃圾回收时,都需要暂停用户线程,CMS(Concurrent Mark Sweep)收集器是一种以 获取最短停顿时间 为目标的收集器,重视服务的响应速度,希望系统停顿时间最短,能给用户带来良好的体验。
CMS收集器是基于"标记-清除"算法实现的,它的运作过程比较复杂,整个过程分为四个步骤:
整个过程中耗时最长的并发表及和并发清除过程收集线程可以与用户线程一起工作,所以整体上来说,CMS收集器的内存回收过程与用户线程一起并发执行。
CMS是一款优秀的收集器,主要优点:并发、低停顿
CMS关注点是尽可能的缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量,由于与吞吐量密切相关,Parallel Scavenge收集器也经常称为"吞吐量优先"收集器
Serial Old是Serial收集器的老年代版本,同样是单线程收集器,使用标记-整理算法。
Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和标记-整理算法
在注意吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge加 Parallel Old收集器
这个收集器是在JDK1.6中才开始提供的,在此之前Parallel Scavenge一直处于尴尬的状态。原因是如果新生代选择了Parallel Scavenge收集器,老年代除了Serial Old别无选择,由于老年代Serial Old性能上的拖累,使用了Parallel Scavenge收集器也未必能在整体应用上获得吞吐量的最大化效果,直到Parallel Old收集器出现后,"吞吐量优先"收集器终于有了名副其实的应用组合
JDK1.6之前 Parallel Scavenge + Serial Old
JDK1.6以及之后 Parallel Scavenge + Parallel Old
G1垃圾回收器是用在heap memory很大的情况下,把heap划分为很多很多的region块,然后并行的对其进行垃圾回收。
G1垃圾回收器在清除实例所占用的内存后,还会做内存压缩。
G1垃圾回收器回收region的时候基本不会Stop The World,从整体来看是基于标记-整理算法,从局部(两个region之间)来看基于复制算法。
一个region有可能属于Eden、Survivor或者Tenured内存,图中的E表示Eden区,S表示Survivor区、T表示Tenured区、空白就是未使用的空间。G1垃圾收集器还增加了一种新的内存区域,叫做Humongous内存区域,如图中的H块。这种内存区域主要用于存储大对象-即大小超出一个region大小的50%的对象
在G1垃圾收集器中,年轻代的垃圾回收过程使用复制算法
,把Eden区和Survivor区的对象复制到新的Survivor区域
对于老年代的垃圾收集,G1(Garbage First)也分为四个阶段,基本与CMS垃圾收集器一样,但是略有不同