JVM (九)经典的垃圾回收器

349 阅读7分钟

1.serial收集器

  • 1.serial是一个单线程的垃圾收集器,每次只会使用一个线程去回收垃圾对象

  • 2.serial收集器在回收垃圾时,会发生STW

  • 3.serial垃圾收集器作用于新生代,采用复制算法

serial垃圾搜集过程: image.png

优点:

  • 1.采用单核进行垃圾回收,没有线程切换的开销

  • 2.简单高效,是所有垃圾收集器中额外内存消耗最少的

  • 3.是HotSpot虚拟机在客户端模式下默认的新生代垃圾收集器

2.ParNew收集器

  • 1.ParNew是serial的多线程版本,其他特性与serial一致

  • 2 .一般与CMS配合使用

    1. ParNew垃圾收集器作用于新生代,采用复制算法

垃圾收集过程: image.png

优点:

  • 1.在多线程条件下尽量减少垃圾收集STW的时长

  • 2.但线程环境下并不比serial的效率高,在多线程的环境下才能发挥优势

3.Parallel Scavenge收集器

  • 1.Parallel Scavange收集器,作用于 新生代,采用 复制算法

  • 2.Parallel Scavange收集器的目的是为了达到一个可控制的吞吐量

  • 3.Parallel Scavange可以设置最大的停顿时间,-XX:MaxGCPauseMillis

  • 4.Parallel Scavange可以设置垃圾回收的最大时间占比 -XX:GCTimeRatio

Parallel的工作方式:

1.开启Parallel Scavenge垃圾收集器

2.设置最大堆内存 -Xmx

3.设置最大的停顿占比,或者设置最大的停顿时间

4.虚拟机会根据设置的参数,自动调整新生代的大小,Eden区与Survivor区的比例,晋升到老年代的对象的年龄值等参数,达到符合要求的停顿时间或者最大吐吞量.

4.Serial Old收集器

  • 1.serial old 是Serial收集器的老年代版本,作用于老年代,使用标记整理算法

  • 2.serial old的现在的作用是作为CMS收集器发生Concurrent Mode Failure时的备用方案

Serial与Serial old 的运行示意图

image.png

5.Parallel Old收集器

  • 1.Parallel收集器在JDK1.6时提供了用于执行老年代垃圾收集的 Parallel Old收集器,用来代替老年代的Serial Old收集器。

  • 2.Parallel Old收集器采用了标记一压缩算法,但同样也是基于并行回收和”Stop一the一World"机制。

  • 3 .在程序吞吐量优先的应用场景中,Parallel 收集器和Parallel Old收集器的组合,在Server模式下的内存回收性能很不错。

  • 4.在Java8中,默认是此垃圾收集器

Parallel Old的运行流程

image.png

6.CMS

  • 1.CMS是为了获得最短停顿时间为目的的一块老年代垃圾收集器

  • 2.采用标记清楚算法,整个过过程分为初始标记,,并发标记,重新标记,并发清除四个部分

  • 3.除了初始标记与重新标记阶段需要发生STW外,其他两个阶段都是与应用线程并发进行垃圾清除

  • 4.当老年代达到一定的阈值就会触发CMS,并且要预留一定的空间给新的对象进行分配,如果没有空闲的内存空间,会发生Concurrent Mode Failture,冻结用户线程的执行,临时启用Serial Old收集器来重新进行老年代的垃圾收集

  • 5.CM S是一款基于“标记-清除”算法实现的收集器,。空间碎片过多时,将会给大对象分配带来很大麻烦,往往会出现老年代还有很多剩余空间,但就是无法找到足够大的连续空间来分配当前对象,而不得不提前触发一次Full GC的情况。

image.png

  • 初始标记:初始标记仅仅只是标记一下GCRoots能直接关联到的对象,速度很快;

  • 并发标记:就是从GC Roots的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行;

  • 重新标记:修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,防止在并发标记阶段被重新引用的对象被回收

  • 并发清除:清理删除掉标记阶段判断的已经死亡的对象,由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的

7.G1收集器

  • 1.G1收集器是面向局部收集和基于Region的内存布局的,G1收集器将内存区域划分为大小相等的region区域,每次只回收部分的region.

image.png

  • 2.G1 GC有计划地避免在整个Java 堆中进行全区域的垃圾收集。G1跟踪各个Region 里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region。

  • 3.G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。

  • 4.Region中还有一类特殊的Humongous区域,专门用来存储大对象。G1认为只要大小超过了一个Region容量一半的对象即可判定为大对象。

  • 5.G1为了解决跨Region引用对象的应用问题,避免编辑阶段全堆扫描,使用记忆集避免全堆作为GC Roots扫描,它的每个Region都维护有自己的记忆集,这些记忆集会记录下别的Region指向自己的指针

  • 6.:CM S收集器采用增量更新算法实现,而G1收集器则是通过原始快照(SATB)算法来实现的。此外,垃圾收集对用户线程的影响还体现在回收过程中新创建对象的内存分配上,程序要继续运行就肯定会持续有新对象被创建,G1为每一个Region设计了两个名为TAM S(Top at M ark Start)的指针,把Region中的一部分空间划分出来用于并发回收过程中的新对象分配,并发回收时新分配的对象地址都必须要在这两个指针位置以上.

  • 7.最终标记与筛选回收会发生STW

image.png

  • 初始标记(Initial M arking):仅仅只是标记一下GC Roots能直接关联到的对象,这个阶段需要停顿线程,但耗时很短,而且是借用进行Minor GC的时候同步完成的,所以G1收集器在这个阶段实际并没有额外的停顿。

  • 并发标记(Concurrent M arking):从GC Root开始对堆中对象进行可达性分析,递归扫描整个堆里的对象图,找出要回收的对象,这阶段耗时较长,但可与用户程序并发执行。当对象图扫描完成以后,还要重新处理SATB记录下的在并发时有引用变动的对象。

  • 最终标记(Final M arking):对用户线程做另一个短暂的暂停,用于处理并发阶段结束后仍遗留下来的最后那少量的SATB记录。

  • 筛选回收(Live Data Counting and Evacuation):负责更新Region的统计数据,对各个Region的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,可以自由选择任意多个Region构成回收集,然后把决定回收的那一部分Region的存活对象复制到空的Region中,再清理掉整个旧Region的全部空间。这里的操作涉及存活对象的移动,是必须暂停用户线程,由多条收集器线程并行完成的。