垃圾回收算法,我们已经了解过。
那么有哪些垃圾收集器?它们的使用场景是什么?
它们又是如何运用垃圾回收算法来进行垃圾回收的呢?
新生代的收集器。采取的复制算法。
单线程的收集器,它只会使用一个CPU或一条收集线程去完成垃圾收集工作。
在它进行垃圾收集时,必须暂停其他所有的用户线程,直到它收集结束。
HotSpot虚拟机为消除或者减少工作线程因内存回收而导致停顿的努力一直在进行着。
Serial收集器是虚拟机运行在Client模式下的默认新生代收集器。也是比较好的选择。
ParNew收集器其实就是Serial收集器的多线程版本。也就是虚拟机会使用多线程来进行垃圾回收,但仍然是停止所有的用户线程。
它是许多运行在Server模式下的虚拟机中首选的新生代收集器。
可以与CMS老年代的垃圾收集器配合使用。
ParNew收集器在单CPU的环境中绝对不会有比Serial收集器更好的效果。当然随着使用的CPU的数量的增加,它对于GC时系统资源的有效使用还是很有好处的。
默认开启的线程数与CPU数量相同。可以使用参数来指定垃圾收集的线程数目。
新生代的收集器,使用复制算法。并行的线程收集器。
关注点与其他收集器不同,其他收集器的关注点是尽可能的缩短垃圾收集时用户线程的停顿时间。
而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量。
所谓吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值。
吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间),例如每100分钟的时间里,需要1分钟的时间做垃圾收集,那么吞吐量就是99%。
停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验。
高吞吐量则可以高效地利用CPU时间,尽快完成程序的运算任务。主要适合在后台运算而不需要太多交互的任务。
Parallel Scavenge收集器提供了两个参数用于精确控制吞吐量,它是吞吐量优先的收集器。
是Serial 收集器的老年代版本,也是一个单线程的收集器。
使用标记—整理算法。
这个收集器的主要意义也是在于给Client模式下的虚拟机使用。
Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和标记—整理算法。
在注重吞吐量及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge加Parallel Old收集器。
以获取最短回收停顿时间为目标的收集器。给用户带来较好的体验。并发收集,低停顿。
使用标记—清除算法实现的。
整个过程分为4个步骤:
由于整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作,所以,从总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。
CMS收集器的缺点:
G1是一款面向服务端应用的垃圾收集器,具备以下特点:
G1将整个Java堆划分为多个大小相等的独立区域Region,虽然还保留新生代与老年代的概念,但新生代和老年代不再是物理隔离的了。它们都是一部分Region(不需要连续)的集合。
G1之所以能建立可预测的停顿时间模型,是因为它可以有计划地避免在整个Java堆中进行全区域的垃圾收集,它跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region。
在G1收集器中,Region之间的对象引用,以及其他收集器中的新生代与老年代之间的对象引用,虚拟机都是使用Remembered Set来避免全堆扫描的。G1中的每个Region都有一个与之对应的Remembered Set,记录对象被哪些地方引用,在GC根节点的枚举范围中加入Remembered Set即可保证不对全堆扫描也不会有遗漏。
如果不计算维护Remembered Set的操作,G1收集器的运作大致可划分为以下几个步骤:
一表胜前言:
新生代/老年代 | Serial Old—老年代 | Parallel Old—老年代 | CMS—老年代 | G1 |
---|---|---|---|---|
Serial—新生代 | Y | N | Y | N |
ParNew—新生代 | Y | N | Y | N |
Parallel Seavenge—新生代 | Y | Y | N | N |
G1 | N | N | N | Y |
以上表格是垃圾收集器的一个搭配总结,可以搭配使用的是Y,不可以搭配使用的是N。
从表格中可以看到: