jvm垃圾回收算法及收集器使用总结

几种垃圾回收算法

  1. 标记清除算法

  2. 复制算法算法

  3. 标记整理算法

标记清除算法

此方法会遍历两次,第一次将可回收的对象进行标记,第二次遍历把标记的对象清除

640?wx_fmt=png

优点: 简单,易实现
缺点: 容易产生内存碎片,对于后面分配大空间时,找不到足够的空间,而主动会触发一次内存回收,增加内存回收的次数

复制算法

此方法将内存按容量分为两块,例如A、B两块,每次只使用其中的一块,当要进行回收操作时,将A中还存活的对象复制到B块中(假设上次使用A),然后对A中所有对象清空就又构成一个完整的内存块。这种方法就避免了标记清除的内存碎片问题。

640?wx_fmt=png

优点: 快速高效,不会产生内存碎片。
缺点: 可用内存会减少一半,因为是按照均分的。 

标记整理算法

复制算法在对象存活率较高的场景下要进行大量的复制操作,效率很低。万一对象100%存活,那么需要有额外的空间进行分配担保。老年代都是不易被回收的对象,对象存活率高,因此一般不能直接选用复制算法。而标记清理算法会产生内存碎片,所以有人提出了另外一种标记-整理算法,过程与标记-清除算法一样,但不是直接清除标记可回收的对象,是移动所有的存活的对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收,其是在标记-清除算法的基础上进行了移动,成本更高,但是解决了内存碎片的问题,标记-整理算法的工作过程如图

640?wx_fmt=png

优点: 适合存活对象多的,不产生内存碎片 

几种垃圾收集器

1.Serial收集器(-XX:+UseSerialGC,复制算法)

采用复制算法的单线程垃圾收集器,也因为是单线程,所以在进行垃圾收集的时候,必须暂停所有的工作进程,直到收集结束,关注的是用户停顿时间,不过这个收集器依然是client模式下的默认年轻代收集器,因为其简单高效

2.Serial old收集器(-XX:+UseSerialOldGC,标记-整理算法)

除了算法是使用的标记-整理算法,其余的和年轻代一样,就是serial的老年代版本,都是单线程收集,且在垃圾收集的时候,必须暂停所有的工作进程,是client模式下的默认的老年代收集器

3.ParNew收集器(-XX:+UseParNewGC,复制算法)

就是serial收集器的多线程版本,其他的和serial收集器一模一样,也是用于在年轻代收集,在单核下,执行效率不如serial收集器,但是在多核下,执行会有优势,在CPU数量非常多的情况下,可以使用-XX:ParallelGCThreads参数来限制垃圾收集的线程数。

4.Parallel Scavenge收集器(-XX:+UseParallelGC,复制算法)

和parnew收集器类似,都是多线程的复制算法收集器,也是用于年轻代收集,但是比起关注用户线程的停顿时间,更加关注系统的吞吐量,在多核下执行才有优势,是server模式下的默认的年轻代垃圾收集器,虚拟机提供了-XX:MaxGCPauseMillis和-XX:GCTimeRatio两个参数来精确控制最大垃圾收集停顿时间和吞吐量大小。不过不要以为前者越小越好,GC停顿时间的缩短是以牺牲吞吐量和新生代空间换取的。Parallel Scavenge收集器有一个-XX:+UseAdaptiveSizePolicy参数,这是一个开关参数,这个参数打开之后,就不需要手动指定新生代大小、Eden区和Survivor参数等细节参数了,虚拟机会根据当前系统的运行情况以及性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量。如果对于垃圾收集器运作原理不太了解,以至于在优化比较困难的时候,使用Parallel Scavenge收集器配合自适应调节策略,把内存管理的调优任务交给虚拟机去完成将是一个不错的选择。

ps:停顿时间短适合需要与用户交互的程序,良好的响应速度能提升用户体验;高吞吐量则可以高效率利用CPU时间,尽快完成运算任务,主要适合在后台运算而不需要太多交互的任务。

5.Parallel Old收集器(-XX:+UseParallelOldGC,标记-整理算法)

Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。这个收集器在JDK 1.6之后的出现,在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge收集器+Parallel Old收集器的组合

6.CMS收集器(-XX:+UseConcMarkSweeoGC,标记-清除算法)

CMS收集器是以获取最短回收停顿时间为目标的收集器,用于老年代收集,使用标记 - 清除算法,根据GC日志把收集过程分为7步

1.CMS Initial Mark

CMS初始化标记的阶段,从垃圾回收的"根对象"(GC Root)开始,扫描与"根对象"直接关联的对象,并做标记,在此期间,其他线程都会停止,会有短暂的stop-the-world

2.CMS-concurrent-mark

并发标记阶段,与其他应用线程并发执行,时间很长,目的是从"根对象"开始对堆中对象进行可达性分析,找出存活的对象。同时,由于该阶段是用户线程和GC线程并发执行,对象之间的引用关系在不断发生变化,对于这些对象,都是需要进行重新标记的,否则就会出现错误。为了提升重新标记的效率,JVM 会使用写屏障(write barrier)将发生引用关系变化的对象所在的区域对应的 card 标记为 dirty,后续只需要扫描这些dirty card区域即可,避免扫描整个老年代。

3.CMS-concurrent-preclean

并发预清理阶段,也是与应用线程并发执行的,该阶段存在的意义主要是为了尽可能降低 Final Remark 阶段的耗时,因为 Final Remark 阶段是 stop-the-world 的。该阶段主要做的事是将上一阶段被标记为 dirty 的 card 所对应的区域进行重新扫描标记,处理并发阶段发生引用变化的对象。

4.CMS-concurrent-abortable-preclean

并发可中止预清理阶段,该阶段和并发预处理做的事是基本一样的,也是主要处理 dirty card。区别在于并发预处理只执行一次,而本阶段会一直循环执行,直到触发终止条件:

循环次数超过阈值 CMSMaxAbortablePrecleanLoops,默认是0,也就是没有循环次数的限制。

处理时间达到了阈值 CMSMaxAbortablePrecleanTime,默认是5秒。

Eden区的内存使用率达到了阈值 CMSScheduleRemarkEdenPenetration,默认为50%。

5.CMS Final Remark

重新标记阶段,会暂停所有的应用线程,会有较长的stop-the-world,该阶段的任务是标记整个年老代的所有的存活对象,这里日志字段解释:

YG occupancy : 年轻代当前占用情况和容量

Rescan (parallel) : 重新标记所花的时间

weak refs processing : 处理弱引用所花的时间

class unloading : 卸载无用的class所花的时间

scrub symbol table 与 scrub string table : 清理类元数据及内部字符串所花的时间

6.CMS-concurrent-sweep

并发清理阶段,与应用线程并发执行,这个阶段的目的就是移除那些不用的对象,回收他们占用的空间。

7.CMS-concurrent-reset

开始并发重置。在这个阶段,与CMS相关的对象被重新初始化,这样下一个周期可以正常进行。

7.G1(Garbage First)收集器(-XX:+UseG1GC,复制+标记-整理算法)

既可以用于年轻代,又可以用于老年代的收集器,G1算法将堆划分为若干个区域(Region),它仍然属于分代收集器。不过,这些区域的一部分包含新生代,新生代的垃圾收集依然采用暂停所有应用线程的方式,将存活对象拷贝到老年代或者Survivor空间。老年代也分成很多区域,G1收集器通过将对象从一个区域复制到另外一个区域,完成了清理工作。这就意味着,在正常的处理过程中,G1完成了堆的压缩(至少是部分堆的压缩),这样也就不会有cms内存碎片问题的存在了。在G1中,还有一种特殊的区域,叫Humongous区域,用于存放巨型对象的。

G1特点:

  1. 并行和并发。使用多个CPU来缩短Stop The World停顿时间,与用户线程并发执行。
  2. 分代收集。独立管理整个堆,但是能够采用不同的方式去处理新创建对象和已经存活了一段时间、熬过多次GC的旧对象,以获取更好的收集效果。
  3. 空间整合。基于标记 - 整理算法,无内存碎片产生。
  4. 可预测的停顿,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。

ps:虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分(可以不连续)Region的集合

垃圾收集器搭配使用

有连线的代表可以组合使用

垃圾回收器总览.png

 

本文参考:

Java基础篇——JVM之GC原理(干货满满) - 会炼钢的小白龙 - 博客园

Java GC(垃圾回收机制) - year12 - 博客园

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值