HotSpot虚拟机全部的垃圾收集器以下图:算法
上面有7种收集器,分为部分,上面为新生代收集器,下面是老年代收集器。若是两个收集器之间存在连线,就说明它们能够搭配使用。多线程
新生代的收集器使用复制算法,
老年代使用并发标记清除(CMS)或标记-整理算法。并发
Java中Stop-The-World机制简称STW,是在执行垃圾收集算法时,Java应用程序的其余全部线程都被挂起(除了垃圾收集帮助器以外)。Java中一种全局暂停现象,全局停顿,全部Java代码中止,native代码能够执行,但不能与JVM交互。spa
序号 | 收集器 | 收集范围 | 算法 | 执行类型 |
---|---|---|---|---|
1 | Serial | 新生代 | 复制 | 单线程 |
2 | ParNew | 新生代 | 复制 | 多线程并行 |
3 | Parallel | 新生代 | 复制 | 多线程并行 |
4 | Serial Old | 老年代 | 标记整理 | 单线程 |
5 | CMS | 老年代 | 标记清除 | 多线程并发 |
6 | Parallel Old | 老年代 | 标记整理 | 多线程 |
7 | G1 | 所有 | 复制算法,标记-整理 | 多线程 |
解释:
并行(Parallel):多条垃圾收集线程并行工做,而用户线程仍处于等待状态
并发(Concurrent):垃圾收集线程与用户线程一段时间内同时工做(交替执行)线程
Serial收集器是一个新生代收集器,单线程执行,使用复制算法。它在进行垃圾收集时,必 须暂停其余全部的工做线程(用户线程)。是Jvm client模式下默认的新生代收集器。对于限定单个CPU的环境来讲,Serial收集器因为没有线程交互的开销,专心作垃圾收集天然能够得到最高的单 线程收集效率。对象
ParNew收集器其实就是serial收集器的多线程版本,除了使用多条线程进行垃圾收集以外,其他行为与Serial收集器同样。blog
Parallel Scavenge收集器也是一个新生代收集器,它也是使用复制算法的收集器,又是并行多线程收集器。parallel Scavenge收集器的目标则是达到一个可控制的吞吐量。吞吐量= 程序运行时间/(程序运行时间 + 垃圾收集时间),虚拟机总共运行了100分钟。其中垃圾收集花掉1分钟,那吞吐量就是99%。内存
使用以下2个参数进行控制吞吐量资源
示意图和ParNew相似(参见图3-7)。rem
Serial Old是Serial收集器的老年代版本,它一样使用一个单线程执行收集,使用“标记-整理”算法。主要使用在Client模式下的虚拟机。若是在Server模式下,它主要还有两大用途:一个是在JDK 1.5及以前的版本中与Parallel Scavenge收集器搭配使用,另一个就是做为CMS收集器的后备预案。若是CMS收集器出现Concurrent Mode Failure,则Serial Old收集器将做为后备收集器。
详见图3-6 老年的收集
Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。CMS收集器是基于“标记-清除”算法实现的,整个收集过程大体分为4个步骤:
其中初始标记、从新标记这两个步骤任然须要停顿其余用户线程。初始标记仅仅只是标记出GC ROOTS能直接关联到的对象,速度很快,并发标记阶段是进行GC ROOTS 根搜索算法阶段,会断定对象是否存活。而从新标记阶段则是为了修正并发标记期间,因用户程序继续运行而致使标记产生变更的那一部分对象的标记记录,这个阶段的停顿时间会被初始标记阶段稍长,但比并发标记阶段要短。
因为整个过程当中耗时最长的并发标记和并发清除过程当中,收集器线程均可以与用户线程一块儿工做,因此总体来讲,CMS收集器的内存回收过程是与用户线程一块儿并发执行的。
CMS收集器的优势:并发收集、低停顿,可是CMS还远远达不到完美,器主要有三个显著缺点:
CMS收集器对CPU资源很是敏感。
在并发阶段,虽然不会致使用户线程停顿,可是会占用CPU资源而致使引用程序变慢,总吞吐量降低。CMS默认启动的回收线程数是:(CPU数量+3)/4。(建议CPU个数最少4个)。
没法处理浮动垃圾
在作垃圾回收的过程当中会产生新的垃圾(并行执行),因此须要预留一部分空间给用户线程使用。
可使用-XX:CMSInitiatingOccupancyFraction(jdk1.6 默认为92%)参数来设置,预留多少空间开始作GC。若是在垃圾回收的过程当中,剩余空间不足仍然知足不了用户线程生成对象所须要的空间,就会出现“Concurrent Mode Failure”失败,这时候虚拟机将启动后备预案:临时启用Serial Old收集器来从新进行老年代的垃圾收集,这样停顿时间就很长了。
CMS是基于“标记-清除”算法实现的收集器,使用“标记-清除”算法收集后,会产生大量碎片。
空间碎片太多时,将会给对象分配带来不少麻烦,好比说大对象,内存空间找不到连续的空间来分配不得不提早触发一次Full GC。为了解决这个问题,CMS收集器提供了一个-XX:UseCMSCompactAtFullCollection开关参数,用于在Full GC以后增长一个碎片整理过程,还可经过-XX:CMSFullGCBeforeCompaction参数设置执行多少次不压缩的Full GC以后,跟着来一次碎片整理过程。
七、G1收集器
G1(Garbage First)垃圾回收器是用在heap memory很大的状况下,把heap划分为不少不少的region块,而后并行的对其进行垃圾回收。
G1垃圾回收器在清除实例所占用的内存空间后,还会作内存压缩。
G1垃圾回收器回收region的时候基本不会STW,而是基于 most garbage优先回收 的策略来对region进行垃圾回收的。
结果以下图:
一个region有可能属于Eden,Survivor或者Tenured内存区域。图中的E表示该region属于Eden内存区域,S表示属于Survivor内存区域,T表示属于Tenured内存区域。图中空白的表示未使用的内存空间。G1垃圾收集器还增长了一种新的内存区域,叫作Humongous内存区域,如图中的H块。这种内存区域主要用于存储大对象-即大小超过一个region大小的50%的对象。
在G1垃圾收集器中,年轻代的垃圾回收过程使用复制算法。把Eden区和Survivor区的对象复制到新的Survivor区域。
以下图:
对于年老代上的垃圾收集,G1垃圾收集器也分为4个阶段,基本跟CMS垃圾收集器同样,但略有不一样:
Initial Mark阶段 - 同CMS垃圾收集器的Initial Mark阶段同样,G1也须要暂停应用程序的执行,它会标记从根对象出发,在根对象的第一层孩子节点中标记全部可达的对象。可是G1的垃圾收集器的Initial Mark阶段是跟minor gc一同发生的。也就是说,在G1中,你不用像在CMS那样,单独暂停应用程序的执行来运行Initial Mark阶段,而是在G1触发minor gc的时候一并将年老代上的Initial Mark给作了。
Concurrent Mark阶段 - 在这个阶段G1作的事情跟CMS同样。但G1同时还多作了一件事情,就是若是在Concurrent Mark阶段中,发现哪些Tenured region中对象的存活率很小或者基本没有对象存活,那么G1就会在这个阶段将其回收掉,而不用等到后面的clean up阶段。这也是Garbage First名字的由来。同时,在该阶段,G1会计算每一个 region的对象存活率,方便后面的clean up阶段使用 。
Remark阶段 - 在这个阶段G1作的事情跟CMS同样, 可是采用的算法不一样,G1采用一种叫作SATB(snapshot-at-the-begining)的算法可以在Remark阶段更快的标记可达对象。
Clean up/Copy阶段 - 在G1中,没有CMS中对应的Sweep阶段。相反 它有一个Clean up/Copy阶段,在这个阶段中,G1会挑选出那些对象存活率低的region进行回收,这个阶段也是和minor gc一同发生的,以下图所示: