首页 > 编程知识 正文

g1垃圾收集器过程,g1和cms的区别

时间:2023-05-06 04:24:55 阅读:14997 作者:1253

另一方面,cms收集器cms作为用户线程和收集线程同时运行的收集器,其设计理念可以减少(低停顿)停顿时间,如何减少? 最好的方法是充分利用cpu,使其能够同时运行(多线程)。

是否也在运行用户线程? 对象的参照位置会不会发生变更? 如果更改堆中对象的内存地址,则用户线程将无法移动到引用对象,并且无法执行。 什么算法在运行过程中不更改对象呢?

请考虑一下jvm回收的算法:

1、标志的清理(好像只有标志。 然后,原始对象没有移动),但会发生内存碎片

2、复制(将内存分成两部分,将生存对象复制到另一个内存块),对象明显移动,不能

3、组织标记(将活动对象移动到一端,从另一端组织),明显对象也不能移动

通过分析这三种算法,似乎只有一种能满足cms的设计理念。 因此,为了即使有缺陷也能够并行化,cms选择了清除算法。

cms收集流程

初始标记同时标记重新标记同时清理

请理解以下四个过程。

1、初始标记:独占CPU、stop-the-world,只标记gcRoots可以直接关联的对象

2、同时标记:标记所有可以与用户线程同时运行且可以通过gcRoots tracing访问的对象

3、重新标注:独占CPU、stop-the-world,对同时标注阶段用户线程执行产生的垃圾对象进行标注修改,更新在自我救济部分逃跑的对象

4、同步清理:可以与用户所在线程同时运行,清理垃圾

好处:

1、同步执行

2、减少停顿时间(低停顿) )。

缺点:

1、因为是并发,所以对cpu很敏感,在并发阶段用户线程不会停止,但是由于占用了一部分线程,所以APP应用会变慢

2、无法处理漂浮垃圾。 在同步清理过程中,一些用户线程还在继续工作,因此这一部分产生的垃圾被称为漂浮垃圾,只能在下一个过程中清理。 另一个需要注意的是,用户线程仍在运行,以确保一定的内存空间。 内存空间不足时,会发生“Concurrent Mode Failure”(并发模式故障),发生此情况时会打开备份计划,并临时使用SeialOld收集器进行收集工作

3、由于采用了标签清理算法,会导致大量的内存碎片(空间不连续)。 碎片过多会给大对象空间的分配带来很大的麻烦,往往会发生。 老一代还有很大的空间,但年轻一代没有足够的连续空间分配给该对象,因此必须提前触发full GC (minor GC )。 为了解决这个问题,cms提供了一个

(CMS默认打开UseCMSCompactAtFullCollection参数,在FullGC时进行内存碎片整理合并。 内存碎片已经解决,但负面影响是停顿时间变长了。 另一个cmsFullGCsBeforeCompaction参数控制FullGC要清理多少次。 默认值为0,表示每个完整GC都进行碎片整理font,CMS无法承受。 在执行FullGC时打开内存碎片整理进程,但不会同时执行内存碎片整理进程,因此不会发出内存碎片整理程序,但会产生暂停时间

CMS发生完全通用汽车的原因:

1、内存碎片太多,年轻一代晋升到老年代,没有足够的空间,提前做全GC

2、同时进行中jvm在同时进行结束前感觉堆已满,需要提前触发全GC

注意:

1、初始标记时,无法到达的对象在本次GC中一定会被回收。 例如,对象f

2、被标记的对象,即使最终不再引用此次GC也不会被回收。 例如,对象c

初始标记(未出现在图中,请参阅步骤a ) :初始标记时在a上做了标记。

步骤a :标记a参考的对象bc和b参考的对象e,并且abcegd基于那个时候的对象参考关系而生存。

步骤b :对象的引用关系发生改变,b不再引用c,新引用d,g不再引用d

步骤c )同时标记过程完成,标记abceg。 第二个和第四个区域中对象的引用关系已更改并记录。 这使用了card table、mod union table数据结构、write barrier技术,稍后说明。

步骤d :实际上是重新标记的结果,可以看到对象d在同时标记结束时未被标记,但它仍被对象b引用,不应该回收。 这取决于重新标记阶段对dirty card (对象参考关系发生变化的区域)的处理。

CMS失败后使用备案SerialOld收集器

二、G1 g1面服务端APP应用垃圾回收器的初始标记-并发标记-最终标记-过滤回收只能在并发标记阶段同时执行用户线程和收集线程,无需与其他收集器合作,即可独立管理整个GC堆

特点:

1、并行同时: g1可以充分利用多核硬件环境下cpu的优势,使用多个cpu减少停机时间。 其他一些收集器可能需要停止java线程执行的gc操作,但g1收集器可以同时运行并继续执行java程序

2、分代收集: g1可以独立管理整个gc堆栈,而不需要与其他收集器合作,但他不同

方式处理新创建的对象和已经存活了一段时间、熬过多次gc的旧对象以获取更好的回收效果。所以g1可以自己管理正直的大叔代和老年代。
3、空间整合,没有内存碎片产生:由于g1使用了独立的区域(region)概念,g1从整体来看是基于“标记-整理”算法实现收集,从局部(两个region)来看是基于复制算法实现的收集,但无论如何,这两种算法都不会产生内存碎片

在最后筛选回收阶段,对每个Region里的回收对象价值(回收该区域的时间消耗和能得到的内存比值)最后排序,用户可以自定义停顿时间 ,那么g1就可以对部分region进行回收,这使得停顿时间是用户可以自己控制的。
但是每个region之间是存在相关引用关系的,这将导致minorGc时,会同时对老年代进行扫描,甚至全堆扫描,造成minorGc交率低下,时间变的很长。
解决方案:
维护一个remember set 集合用来存放各个region之间的引用关系,当gcRoots tracing时只用扫描set 里的 region 就可以,而不用全堆扫描

4、可预测的停顿:这是g1和相对于cms的另一个特点,降低停顿时间是g1和cms共同的关注点,但g1除发追求低停顿外,还能建立可预测的停顿模型,能让使用这明确指定一个长度为M毫秒时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。

最后: 与其它收集器相比,G1变化较大的是它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留了正直的大叔代和来年代的概念,但正直的大叔代和老年代不再是物理隔离的了它们都是一部分Region(不需要连续)的集合。同时,为了避免全堆扫描,G1使用了Remembered Set来管理相关的对象引用信息。当进行内存回收时,在GC根节点的枚举范围中加入Remembered Set即可保证不对全堆扫描也不会有遗漏了。

最后筛选回收阶段首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划(可预测的停顿),这一过程同样是需要停顿线程的,但Sun公司透露这个阶段其实也可以做到并发,但考虑到停顿线程将大幅度提高收集效率,所以选择停顿。
参考资料:
JVM: G1和CMS的区别

CMS垃圾收集器运行原理

G1收集器图解

垃圾收集器G1和ZGC详解

案例:
1、将gc日志打印出来。可以在虚拟机的启动gc参数中增加-XX:+PrintGCDetails参数,将每次的GC的耗时信息打印出来。
2、分析日志,找到到底是哪些GC阶段导致了GC时间的上涨。
gc日志中基本都是young GC类型的日志,因此不存在Mixed GC中对于old genaration回收所造成的gc时间增加。然后发现了Ref Proc这一过程消耗的比较久:
[Ref Proc: 69.9 ms]
然后迅速的想到了并行开启
-XX:+ParallelRefProcEnabled,并且调大了并行标记的线程 -XX:ConcGCThreads,以及增加了 -XX:G1HeapRegionSize

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。