一些概念
并行(Parallel)
指多条垃圾收集线程并行工做,但此时用户线程仍然处于等待状态。java
并发(Concurrent)
指用户线程与垃圾收集线程同时执行(但不必定是并行的,可能会交替执行),用户程序在继续运行,而垃圾收集程序运行于另外一个CPU上。算法
吞吐量
CPU用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)。虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%。多线程
HotSpot虚拟机的垃圾回收器
Serial
- 最基本的单线程垃圾收集器。使用一个CPU或一条收集线程去执行垃圾收集工做。
- 工做时会
Stop The World
,暂停全部用户线程,形成卡顿。适合运行在Client模式下的虚拟机。
- 用做新生代收集器,复制算法。
ParNew
- Serial收集器的多线程版本,和Serial的惟一区别就是使用了多条线程去垃圾收集。
- 除了Serial,只有它能够和CMS搭配使用的收集器。
- 用做新生代收集器,复制算法。
Parallel Scavenge
- 用做新生代收集器,复制算法。
- 关注高吞吐量,能够高效率地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不须要太多交互的任务。
- Parallel Scavenge收集器提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间的
-XX:MaxGCPauseMillis
参数以及直接设置吞吐量大小的-XX:GCTimeRatio
参数。
Serial Old
- Serial收集器的老年代版本,单线程,标记-整理 算法。
- 通常用于Client模式的虚拟机。
- 当虚拟机是Server模式时,有2个用途:一种用途是在JDK 1.5以及以前的版本中与Parallel Scavenge收集器搭配使用 ,另外一种用途就是做为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用。
Parallel Old
- Parallel Scavenge收集器的老年代版本,使用多线程和 标记-整理 算法。在JDK 1.6中开始提供。
- 在注重吞吐量的场合,配合Parallel Scavenge收集器使用。
CMS(Concurrent Mark Sweep)
- 一种以获取最短回收停顿时间为目标的收集器。适合须要与用户交互的程序,良好的响应速度能提高用户体验。
- 基于 标记—清除 算法。适合做为老年代收集器。
- 收集过程分4步:
- 初始标记(CMS initial mark):只是标记一下GC Roots能直接关联到的对象,速度很快,会
Stop The World
。
- 并发标记(CMS concurrent mark):进行GC Roots Tracing(可达性分析)的过程。
- 从新标记(CMS remark):会
Stop The World
。为了修正并发标记期间因用户程序继续运做而致使标记产生变更的那一部分对象的标记记录,这个阶段的停顿时间通常比初始标记阶段稍长些,但远比并发标记的时间短。
- 并发清除(CMS concurrent sweep):回收内存。
- 耗时最长的并发标记和并发清除过程收集器线程均可以与用户线程一块儿工做,因此时并发执行的。
- 缺点:
- 并发阶段,虽然不会致使用户线程暂停,但会占用一部分线程(CPU资源),致使应用变慢,吞吐量下降。默认启动收集线程数是(CPU数量+3)/4。即当CPU在4个以上时,并发回收时垃圾收集线程很多于25%的CPU资源,而且随着CPU数量的增长而降低。可是当CPU不足4个(譬如2个)时,CMS对用户程序的影响就可能变得很大。
- 没法清除浮动垃圾。并发清除阶段,用户线程还在运行,还会产生新垃圾。这些垃圾不会在这次GC中被标记,只能等到下次GC被回收。
- 标记-清除 算法会产生大量不连续内存,致使分配大对象时内存不够,提早触发Full GC。
G1
- 在JDK1.7提供的先进垃圾收集器。
- 既适合新生代,也适合老年代。
- 空间整合:使用 标记-整理 算法,不产生碎片空间。
- 整个Java堆被分为多个大小相同的的块(region)。新生代和老年代再也不是物理隔离的,而是一部分region块组成的集合。
- 默认把堆平均分红2048个region,最小1M,最大32M,必须是2的幂次方,能够经过
-XX:G1HeapRegionSize
参数指定。region分为4种:
- E:eden区,新生代
- S:survivor区,新生代
- O:old区,老年代
- H:humongous区,用来放大对象。当新建对象大小超过region大小一半时,直接在新的一个或多个连续region中分配,并标记为H
- 可预测的停顿时间:估算每一个region内的垃圾可回收的空间以及回收须要的时间(经验值),记录在一个优先列表中。收集时,优先回收价值最大的region,而不是在整个堆进行全区域回收。这样提升了回收效率,得名:Garbage-First。
- G1中有2种GC:
- young GC:新生代eden区没有足够可用空间时触发。存活的对象移到survivor区或晋升old区。
- mixed GC:当old区对象不少时,老年代对象空间占堆总空间的比值达到阈值(
-XX:InitiatingHeapOccupancyPercent
默认45%)会触发,它除了回收年轻代,也回收 部分 老年代(回收价值高的部分region)。
- mixed GC回收步骤:
- 初始标记(Initial Marking):只是标记一下GC Roots能直接关联到的对象,而且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中建立新对象。这阶段须要停顿线程(STW),但耗时很短,共用YGC的停顿,因此通常伴随着YGC发生。
- 并发标记(Concurrent Marking):进行可达性分析,找出存活对象,耗时长,但可与用户线程并发执行。
- 最终标记(Final Marking):修正并发标记阶段用户线程运行致使的变更记录。会STW,但能够并行执行,时间不会很长。
- 筛选回收(Live Data Counting and Evacuation):根据每一个region的回收价值和回收成本排序,根据用户配置的GC停顿时间开始回收。
- 当对象分配过快,mixed GC来不及回收,G1会退化,触发Full GC,它使用单线程的Serial收集器来回收,整个过程STW,要尽可能避免这种状况。
- 当内存不多的时候(存活对象占用大量空间),没有足够空间来复制对象,会致使回收失败。这时会保留被移动过的对象和没移动的对象,只调整引用。失败发生后,收集器认为存活对象被移动了,有足够空间让应用程序使用,因而用户线程继续工做,等待下一次触发GC。若是内存不够,就会触发Full GC。
参考G1的详细介绍并发