> 文章列表 > G1垃圾收集器回收步骤

G1垃圾收集器回收步骤

G1垃圾收集器回收步骤

1:类加载机制:

    加、验、准、解、初、使、卸
    加、烟、准、姐、初、湿、鞋

    1.1:加载、将class 文件转化为二进制流加载 JVM 内存中并生成一个该类的Class对象
    1.2:验证、Class 文件的字节流中包含的信息是否符合当前虚拟机的要求
    1.3:准备、在方法区中分配这些类变量所使用的内存空间
    1.4:解析、虚拟机将常量池中的符号引用替换为直接引用的过程
    1.5:初始化、执行类构造器<client>方法,编译器收集类变量的赋值操作和静态语句块中的语句,
                  虚拟机会确保父类的<client>方法已经执行完毕,如果没有静态变量和静态语句则
                  不生成client方法

2:引用:

    强、软、弱、虚/从不/不足/GC后/跟踪回收状态

3:类加载器:

    引导类加载器、扩展类加载器、应用程序类加载器

4:双亲委派机制:

    解释:自己不加载委派给父类去完成,如果无法加载则自己再加载,
    好处:使用不同的类加载器最终得到的都是同样一个 Object 对象

5:JVM:

    5.1:1.7-堆、栈、方法区、程序计数器、本地方法栈
         1.8-堆、栈、元空间(本地内存)、程序计数器、本地方法栈
             默认堆大小:-Xms:1/64,-Xmx:1/4
                 新生代默认:-NewRatio:2,老年代/新生代的值= 2
                 新生代和幸存者区比例:8:1:1
                 新生代大小:-Xmn
                 老年代大小:堆总-新生代

6:调优工具:

|命令行|Jconsole|VisualVM|Jprofiler|Java Flight Recorder|GC Viewer|GC Easy|

6:确定垃圾

    6.1-引用计数法:为对象添加引用计数器,引用它+1,失效时-1
                优点:实现简单,判定效率高,回收没有延时性。
                缺点:需要单独的字段存储增加存储开销。
                      每次赋值增加时间开销。
                      无法处理循环引用的问题。
    6.2-可达性分析法:从GC Roots到这个对象可不可达,
                    没有finalize()方法,直接干掉,
                    有的话加入队列再finalize(),有连接则移除,没有则回收。
                优点:解决循环依赖问题,防止内存泄露
        6.2.1-GC Roots:
            6.2.1.1:各线程调用方法的参数,局部变量
            6.2.1.2:本地方法栈内的引用对象
            6.2.1.3:方法区中静态属性引用对象
            6.2.1.4:常量引用的对象
            6.2.1.5:锁持有的对象
        6.2.2-finalize 方法:销毁之前自己处理逻辑,用于对象回收之前最资源的释放,只能调一次
                会导致对象复活
                执行时间没有保证,若不发生GC则没机会执行
                严重影响性能
        6.2.3-对象的三种状态:
                可触及
                可复活
                不可触及        
    内存泄露:对象不可用并且垃圾收集器无法回收
    内存溢出:没有足够的内存,并且垃圾收集器无法提供更多的空间

6:垃圾回收算法

    6.1-拷贝、标记清除、标记整理
    6.2-分代回收思想
        年轻代-拷贝,年龄+1,到15移到老年代
        老年代-标记整理
    6.3-分区回收思想
        Region

7: 垃圾收集器

    7.1-年轻代:Serial(串)、    ParNew(并)、    Parallel Scavenge(并多、吞)-1.8默认、
    7.2-老年代:Serial Old(串)、CMS(初并重并)、    Parallel Old(并)-1.8默认、
    7.3-堆:G1(并发)
    7.4-CMS的问题:
        7.4.1-占用CPU资源而导致引用程序变慢,总吞吐量下降。默认线程数是:(CPU数量+3) / 4
        7.4.2-CMS收集器无法处理浮动垃圾
        7.4.3-需要预留空间供并发收集时的程序运作使用,68%时会被激活,
              预留空间不够抛异常,启用Serial Old导致停顿时间过长。
        7.4.4-标记清除,产生碎片。
    G1:
        g1在实现高吞吐量的同时,尽可能的满足垃圾收集器的暂停时间要求
        内存结构:2048个Region,每个Region 大小在1-32M之间,默认年轻代初始大小整堆的5%,最大整堆的60%

        PRT:Per Region Table 是RSet 在内部记录分区的引用情况。
            稀少:直接记录引用对象的卡片索引
            细粒度:记录引用对象的分区索引
            粗粒度:只记录引用情况,每个分区对应一个比特位

        SATB:
            用于记录某个时间点,每个 Region 中包含的对象及其存活标记信息的快照。
            
            写屏障:
        PLAB:
            线程在分配内存时,首先尝试从 PLAB 中分配。
            如果 PLAB 中的空间不足,线程将开始一个新的 PLAB。
            这样能够避免多个线程竞争一个全局分配缓存而导致的性能瓶颈。

G1垃圾回收的理解:

 第一阶段

      1:对象的分配,修改RSet。
      2:年轻代满了触发Young GC
             2.1:初次标记、
             2.2:在并发标记和最终标记的过程中计算出回收价值最大的Region 放入CSet 
             2.3: 根据CSet 进行回收,就是所谓筛选回收。如果大对象大多数已死亡也一并回收。
             2.4:完成回收后,将活得对象放入幸存者区,对象年龄+1,再次修改RSet
       3:有了新的空间用户线程就可以将新的对象放入Eden区了。

第二阶段:

当Young GC 多次后,幸存者区的对象年龄超过15 将进入老年代

第三阶段:

     此时应用线程还在运行,继续产生新的对象,PLAB 用于临时存储从 Eden 区域晋升过来的对象。 在执行垃圾回收操作之前,G1 垃圾回收器会将 PLAB 中的对象依次晋升到老年代中,这样可以减少老年代中的内存分配操作,对于每个线程,G1 垃圾回收器都维护了一个或多个 PLAB。线程在分配内存时,首先尝试从 PLAB 中分配。如果 PLAB 中的空间不足,线程将开始一个新的 PLAB。这样能够避免多个线程竞争一个全局分配缓存而导致的性能瓶颈。

第四阶段:

G1 垃圾回收器在执行 Mixed GC 之前会先记录一份 STAB,
记录 Mixed GC 区域中各个 Region 的存活对象信息和存活标记信息。
之后,G1 垃圾回收器会在 Mixed GC 区域中从存活对象开始,
检查每个已存活的对象所在的 Region,并将这些 Region 标记为 "可复制" 的备选区域。
同时,采用各种启发式算法来选择最佳的 Region 备选列表,
从而在 Mixed GC 期间减少空间碎片,提高内存利用率。

第五阶段:

1:老年代存储达到阈值默认是45% 将触发Mixed GC
2:初次标记。
3:在并发标记和最终标记的过程中,计算出回收价值最大的Region(包含所有区的Region)放入CSet。
4: 根据CSet 进行混合回收。如果大对象少数死亡也回收一部分。
5:将存活的对象拷贝到其他的Region。

第六阶段:

1:拷贝过程中如果发现没有足够的空region能够承载拷贝对象就会触发一次Full GC。
2:此时应用程序的执行会完全停止,进行所有区域的标记和维护操作,以获得充足的空间。

使用场景:

50%以上的堆被存活对象占用
对象分配和晋升的速度变化非常大
垃圾回收时间特别长,超过1秒
8GB以上的堆内存(建议值)
停顿时间是500ms以内

优化:

 1:增加G1垃圾回收器的堆大小:由于G1垃圾收集器使用了分代技术,
       因此需要适当增加堆大小来提高垃圾回收的效率。通常,可以通过设置
       JVM 启动参数 -Xmx 和 -Xms来增加堆大小。

2:设置最大G1回收时间:在优化 G1 垃圾回收器时,需要了解每次垃圾回收所需的时间。
      可以通过设置 JVM 启动参数-XX:MaxGCPauseMillis来控制最大的垃圾回收时间,
      从而提高垃圾回收的效率。

3:调整G1垃圾回收器的分区大小:G1垃圾回收器将堆划分为若干个分区进行垃圾回收。
     可以通过设置 JVM 启动参数 -XX:G1HeapRegionSize 来调整分区大小,
      从而优化垃圾回收器的性能。

4:增加并发线程数:可以通过增加垃圾回收器的并发线程数来提高其效率。
      可以使用 JVM 启动参数 -XX:ConcGCThreads 来增加并发线程数,
      从而提高垃圾回收器的并发性能。

5:避免使用超大对象:G1垃圾回收器的使用应避免创建超大对象。
      超大对象容易导致分配失败、GC 时间过长等问题。

华夏名砚网