美文网首页
垃圾收集机制

垃圾收集机制

作者: 蓝调_4f2b | 来源:发表于2022-11-18 00:36 被阅读0次

    一. 垃圾收集算法

    1. 标记-复制算法

    一般应用于年轻代中,将内存分为相同大小的两块,每次使用其中一块;本次使用完成后,将存活对象复制到另一侧,并清空这块内存。
    问题:该种方式浪费空间

    2. 标记-清除算法

    一般应用于老年代。
    (1)标记阶段:标记存活的对象
    (2)清除阶段:清除未被标记的对象
    (3)问题:效率较低;标记清除后会产生大量不连续空间

    3. 标记-整理算法

    优点:避免内存碎片产生

    二. 垃圾收集器

    垃圾收集器使用图.png

    1. serial收集器(串行收集器)

    (1)使用serial收集器配置:
    -XX: +UseSerialGC
    -XX: +UseSerialOldGC
    (2)串行收集


    串行收集示意图.png

    注:STW(stop the world)暂停所有用户线程,并开始清理系统垃圾,这样做的原因是防止在垃圾清理过程中对象引用发生变化,产生新的未标记到的垃圾。

    2. parallel收集器(JDK8默认)

    (1)开启parallel收集器配置:
    -XX: +UseParallelGC
    -XX: +UseParallelOldGC
    (2)并发收集


    并发收集.png

    3. parNew收集器

    与parallel类型,主要区别为可与CMS配合使用

    4. CMS垃圾收集器

    基于标记-清除算法实现,底层使用写屏障模式
    4.1 流程示意图


    CMS收集器流程.png

    (1)初始标记:执行STW(stop the world),此时用户线程均已停止,垃圾收集器通过引用链分析法找到gc根节点直接引用的对象,该阶段速度极快

    User u = new User();  // 对象u为User类的直接引用
    

    (2)并发标记:并发的含义是应用线程与回收线程并发运行,垃圾收集器将接替初始标记到的对象向下一直寻找堆中的引用,由于此时引用链变得复杂,这部分标记将使用并发标记;相较于STW标记方式,并发标记兼顾了用户线程的执行与垃圾收集,故此处垃圾收集时间将较长

    class Person {
      string p_name;
      int p_id;
    }
    Person p = new Person("xiaoming", 10);
    u.setPerson(p);        // 该引用非直接引用,将在并发标记阶段执行标记
    

    (3)重新标记:修正并发标记期间由于用户行为改变的标记对象,底层使用三色标记法
    (4)并发清理:将未标记的对象进行清除
    (5)并发重置:重置本次GC标记的数据
    (6)CMS的缺点:

    • 对CPU资源较为敏感,并发标记等阶段gc会与用户线程争夺资源
    • 无法处理浮动垃圾,在并发标记和并发清理阶段又产生的垃圾,只能等到下次GC进行处理
    • 底层使用回收算法“标记-清除”导致产生大量碎片,我们可以通过-XX: +UseCMSComputeAtFullCollection,当JVM执行完标记清除后再整理碎片
    • 垃圾收集过程中可能触发concurrent mode failure(并发模式失败):
      在并发标记与并发清理过程中,用户线程将产生新的对象存入老年代,而此时若老年代已满,将激发CMS算法触发full gc(serial old),执行串行STW
      (7)三色标记法(CMS底层算法)
      处理并发标记过程中,对象引用变化的问题;
      会产生漏标的问题,例如以下情况:
    class A {
      B b = new B();
      D d = null;
    }
    class B{
      C c = new C();
      D d = new D();
    }
    class C {}
    public static void main() {
      A a = new A();
      D d = a.b.d;          // 插入读屏障
      a.b.d = null;          // 写屏障
      a.d = d;                // 写屏障
    }
    
    三色标记法.png

    注:最终不回收黑色/灰色对象,只回收白色对象
    (8)对三色标记漏标问题的处理

    • 增量更新方式
      采用缓存记录并发标记过程中扫描的对象,重新标记过程中将从缓存中重新扫描这些对象。


      增量更新方式.png
    • 原始快照方式
      使用缓存方式作为快照集合,将被删除的引用放入集合中记录,并将对象节点标为黑色,成为浮动垃圾,在下轮清理的过程中会清理该种浮动垃圾。
    • 实现增量更新/原始快照方式:写屏障
      给某个对象的成员变量赋值时,在赋值前后进行操作
    void oop_field_store(oop* field, oop new_value) {
      pre_write_barrier(field);
      *field = new_value;
      post_write_barrier(field);
    }
    

    (9)记忆集与卡表
    解决跨代引用问题

    5. G1收集器

    G1收集器将java堆分为大小相等的多个独立区域(Region),种类为:
    Eden区,survive区,old区及Humongous区
    其中Humongous区存放占内存过大对象(一个对象超过region50%,默认被放入Humongous区域)
    (1)G1收集流程


    G1收集流程.png
    • 筛选回收过程:对各个Region回收价值与成本进行排序,依据用户期望GC停顿回收时间制定回收计划(通过-XX:+MaxGCPauseMills修改用户预期停顿阈值),将STW限制在一定时间范围内,增强用户体验
    • 底层采用复制算法回收
    • 优先级列表:考虑gc时间,占用内存空间等
      (2)G1收集算法分类:
    • young GC:计算当前Eden区回收时是否到达设定的时间阈值,不到达该阈值,则继续将对象放入Eden区;到达阈值,则进行一次Young GC
    • mixed GC:回收所有年轻代,部分老年代及Humouongs区域垃圾,是否触发mixed GC由收集阈值确定,阈值的设置通过-XX:InitiatingHeapOccupancyPercent设定。
    • full gc:STW,当老年代完全放满时开始执行,采用单线程进行标记,清理空间
      (3)G1垃圾收集器使用场景:
    • 所用系统的堆中50%以上空间被存活对象占用
    • 对象分配及晋升到老年代的速度变化较大时
    • 垃圾收集时间较长时,比如超过1秒钟
    • 堆内存较大(因为底层使用的是复制算法),超过8GB以上
    • 停顿时间在500ms以内
      注:不同内存推荐使用的算法版本:
    • 堆内存4G以下推荐使用parallel
    • 堆内存4-8G使用CMS+parallel
    • 堆内存8G以上使用G1

    相关文章

      网友评论

          本文标题:垃圾收集机制

          本文链接:https://www.haomeiwen.com/subject/nyvuxdtx.html