SouthLight's Blog


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

JVM垃圾回收机制(二)垃圾收集器

发表于 2020-03-05 | 分类于 java , jvm

前言

垃圾收集器就是内存回收的具体实现,垃圾收集器的主要工作就是清理JVM内存中的垃圾对象

HotSpot的垃圾收集器


上图7种作用于不同分代的垃圾收集器,直线相连说明他们可以搭配使用

新生代的垃圾收集器

Serial

Serial是最基本、历史最悠久的收集器,它主要收集新生代的内存,而且是单线程
特点:单线程、采用复制算法

虽然后续也出现了许多比Serial优秀的收集器,但是它还是JVM在Client模式下的默认新生代收集器,它简单而且高效(与其他收集器的单线程相比—)

PerNew

PerNew收集器是Serial收集器的多线程版本,除了使用多线程进行垃圾收集之外,其他包括Serial收集器的所有控制参数(-XX:SurvivorRatio、-XX:ParetenureSizeThreshold、-XX:HandlePromotionFailure等)、收集算法(复制算法)Stop The World、对象分配规则、回收策略等都与Serial完全一样
特点:多线程、采用复制算法

PerNew是许多运行在Server模式下的首选新生代收集器,而且它是除了Serial之外,唯一一个能与CMS收集器配合工作
相关参数:

  • -XX:+UseConcMarkSweepGD: 因为CMS只能与Serial或者ParNew配合,当指定该参数后,ParNew是默认的新生代收集器,配合CMS
  • -XX:+UseParNewGC: 强制指定ParNew
  • -XX:ParallelGCThreads:限定垃圾收集的线程数

Parallel Scavenge

Parallel Scavenge也是新生代收集器,多线程、采用复制算法,但是它的关注点不同,上面两个的目的是为了尽可能完成垃圾回收的同时,减少GC停顿的时间,而Parallel Scavenge收集器的目的是达到一个可控制的吞吐量(Throughput) 也就是说有高吞吐量,这个吞吐量是指CPU用运行用户代码与CPU总消耗时间的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)
特点:多线程、采用复制算法,但是侧重点不同
停顿时间越短,响应速度越快,用户体验更好;吞吐量越高,就可以高效率的利用CPU时间
相关参数:

  • -XX:MaxGCPauseMills: 控制最大垃圾收集停顿时间,收集器尽可能保证内存回收花费时间不超过该值
  • -XX:GCTimeRatio: 设置吞吐量大小,该值是一个大于0且小于100的整数,也就是垃圾收集时间总总时间的比率,是吞吐量的倒数
  • -XX:+UseAdaptiveSizePolicy: 开关参数,当打开后,不需要手动指定新生代的大小(-Xmn)、Eden与Survivor的比例(-XX:SurvivorRatio)、晋升老年代对象年龄(-XX:PretenureSizeThreshold)等细节参数,虚拟机就会根据系统当前的运行情况,动态调整参数,以达到最大的吞吐量,这种叫做GC自适应的调节策略(GC Ergonomics)
    Parallel Scavenge也称为“吞吐量优先”收集器

老年代的垃圾收集器

Serial Old

Serial Old是Serial收集器的老年代版本,同样是一个单线程收集器,使用“标记-整理”算法,这个收集器主要给Client模式下的虚拟机使用。
如果在Sever模式下,有两大用途:1、在JDK1.5以及之前的版本中与Parallel Scavenge收集器搭配使用;2、作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用。

Parallel Old

Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理算法,在jdk1.6中才开始提供,之前如果新生代使用了Parallel Scavenge收集器,那么老年代只能使用Serial Old,在老年代很大而且硬件条件比较高级的环境中,这种组合的吞吐量比不上ParNew+CMS

CMS

CMS(Concurrent Mark Sweep),是第一款真正意义上的并发(Concurrent)收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作
CMS收集器是一种以获取最短回收停顿时间为目标的收集器,它是基于“标记-清除”算法(名称Mark Sweep)
主要分为4个步骤:

  1. 初始标记(CMS initial mark):stop the world,仅仅只是标记一下GC Root能直接关联到的对象,速度快
  2. 并发标记(CMS concurrent mark):进行GC Roots Tracing
  3. 重新标记(CMS remark): stop the world,修改并发标记期间因用户程序继续运行而导致标记产生变动的那一部分标记记录,这个阶段停顿时间比初始标记稍长,远比并发标记的时间短
  4. 并发清除(CMS concurrent sweep)
    整个过程耗时最长的并发标记和并发清除过程收集器线程可以与用户线程一起工作,所以总体来说CMS收集器是与用户线程一起并发执行

    CMS有以下特点:并发收集、低停顿,但也有明显的缺点
  5. CMS收集器对CPU资源非常敏感(非常占用CPU资源),CMS默认启动的回收线程数量(CPU数量+3)/4,如果CPU负载较高,还要分出一半的运算能力去执行收集器线程,就可能导致用户程序运行速度下降
  6. CMS收集器无法处理浮动垃圾(Floating Garbage),浮动垃圾是指在CMS清理阶段,用户线程还在不断产生新的垃圾,这部分垃圾出现在标记过程之后,CMS无法在当次收集中处理他们,只好留在下一次GC时再清理,这有风险,因为如果在CMS运行期间内存无法满足程序需要,就会出现一次“Concurrent Mode Failure”失败,这是虚拟机启动后被方案:临时启用Serial Old收集器来重新进行老年代的垃圾回收,停顿时间就会变长
  7. 因为采用”标记-清除“算法,空间碎片过多,导致大对象不能分配,不得不提前触发一次Full GC。为了解决这个问题,CMS收集器提供了一个参数-XX:+UseCMSCompactAtFullCollection开关(默认是开启的),用于在CMS收集器要进行FullGC时开启内存碎片的合并整理过程,但是碎片整理无法并发,停顿时间不得不延长。-XX:CMSFullGCsBeforeCompaction这个参数可以设置执行多少次不压缩FullGC后,跟着来一次带压缩的整理(默认是0,表示每次进入FullGC时都进行碎片整理)

G1收集器

G1(Garbage First)收集器在JDK1.7正式使用,它是一款面向服务端应用的垃圾收集器
G1特点:

  1. 并行与并发:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU(或核心)来缩短Stop-The-World停顿的时间
  2. 分代收集:与其他收集器一样,G1也有分代的概念,只是G1可以不需要其他收集器配合就能独立管理整个GC堆
  3. 空间整合:CMS使用“标记-清理”算法,但G1整体上看使用“标记-整理”算法,但是在两个Region之间看是使用“复制”算法实现的,这两种算法意味着G1运作期间不会产生内存碎片
  4. 可预测的停顿:降低停顿时间是G1和CMS共同的关注点,但G1还建立了可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒
    使用G1收集器时,Java堆就划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但是两者不再有物理隔离,它们都是一部分Region(不需要连续)的集合

G1之所以能够建立可预测的停顿时间模型:是因为它可以有计划地避免在整个Java堆中进行全区域的垃圾收集。G1先统计跟踪各个Region里面的垃圾堆积的价值大小,在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region(这也就是Garbage-First名称的来由)。使用Region划分内存空间以及有优先级的区域回收方式,保证了G1收集器在有限的时间内可以获取尽可能高的手机效率

G1如何避免全堆扫描?:使用Remembered Set,每个Region都有一个与之对应的Remembered Set,当程序对Reference类型的数据进行写操作时,会产生一个Write Barrier暂时中断写操作,检查Reference引用的对象是否处于不同的Region(分代的例子就是检查是否老年代中的对象引用了新生代中的对象),如果是,就把引用信息记录到被引用对象所属的Region的Remembered Set之中。当发生GC时,在GC根节点的枚举范围加入Remembered Set即可保证不对全堆扫描

G1收集器的运作步骤:

  1. 初始标记(Initial Marking):标记GC Roots能直接关联到的对象,需要停顿线程
  2. 并发标记(Concurrent Marking):从GC Roots开始对堆中的对象进行可达性分析,可与用户线程并发执行
  3. 最终标记(Final Marking):修改在并发标记期间因用户程序继续运行而导致标记产生变化的记录,需要暂停线程
  4. 筛选回收(Live Data Counting and Evacuation):对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来指定回收计划,这个阶段虽然是可以与用户程序并发执行,但是因为只回收一部分Region,时间是用户可控制的,而且停顿用户线程将大幅度提高收集效率
    上述步骤跟CMS差不多
12…38

SouthLight Lin

38 日志
16 分类
19 标签
© 2020 SouthLight Lin
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4