关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

云南大王-G1垃圾回收器

发布时间:2020-04-13 00:00:00
垃圾回收器的发展历程 背景 01、G1解决的问题 G1垃圾回收器是04年正式提出,12开始正式支持,在17年作为JDK9默认的垃圾处理器。 在04年的时候,java程序堆的内存越来越大,从而导致程序中可存活的活对象越来越多,因此GC的STW时间越来越长。这是G1要解决的主要问题:STW带来的停顿时间太长了。 CMS在此之前效率也很高,但活对象数量一多,STW时间也很长。而且CMS无法解决内存碎片化的问题。 G1还解决的问题是:CMS在GC后,无法compact内存。 02、G1达成的目标 (1)减少由于STW而带来的程序延迟时间,做到伪实时、低延时、可设定目标; 可设定目标是指能够设置GC最大STW停顿的时间,G1会尽量达成目的,但不一定达成。 -XX:MaxGCPauseMillis=N 默认情况下是250毫秒 (2)解决CMS在GC后,无法压缩程序内存的问题; (3)在JDK9之后,默认的垃圾处理器就是G1;它适用于堆内存较大的情况下(>4~6G); G1垃圾回收器 一、G1内存布局 G1不再遵循之前的堆中对象的分代排列,而是将堆分成若干个等大的区域。 而是变成: 默认是分成2048个区域,-XX:G1HeapRegionSize=N 2048 Humongous:当你分配的一个对象超过一半区域的大小时,这个对象就会被放入这个区域。这个区域属于老年代区域。 二、G1的介绍 G1垃圾回收器不再回收整个堆,而是选择一个Collection Set(CS)。而且每次GC时,会估计每个Region中的垃圾比例,优先回收垃圾多的Region。这就为什么被叫做Garbage First算法。这也是为什么G1可以控制STW停顿时间的原因。 G1含有三种GC算法: Full young GC:年轻代GC算法:STW、Parallel、Copying 老年代GC算法:Mostly-concurrent marking、Incremental compaction Mixed GC:混合GC 三、G1引来的问题 问题描述 G1将年轻代、老年代区域划分为许多个小区域,增加在GC判断对象是否为垃圾的难度。比如: 老年代对象可能持有年代代的引用(跨代引用) 不同的Region间的互相引用 假设在Full young GC时,某个年轻代Region对象可能被老年代的某个对象引用,那么我在回收这个年轻代Region时,怎么知道这里面的对象是否被其他Region、老年代引用呢? 问题解决 Remembered Set、Card Table 1、CardTable 每个Region中分为很多区域,每个区域我们成为CardTable,对应的就是上述蓝色区域;每个CardTable有多个entry组成。当对应的内存空间发生改变时,就会标记为dirty。 2、RememberedSet 当Region1的CardTable引用Region2的CardTable时,Region2的RememberedSet就会记录对应CardTable中的entry,可以根据其找到对应的内存区域。 3、解析 当某个内存对应进行赋值是,就是对象的set方法,我们可以在这种方法上添加dirty的描述。 这其实就是典型的时间换空间的做法:用额外的空间维护引用信息,这就是占用5~10%的过多内存占用。 解决方法的实现 1、Write Barrier介绍 Write barrier是一种向JVM注入的一小段代码,用于记录指针变化。比如说object.field = 。 在JVM开始更新指针时,就经过以下几步: 标记Card为Dirty 将Card存入Dirty Card Queue队列中 这里有一个问题:为什么要放在队列里,而不是直接去更新RememberedSet呢? 这是因为JVM运行可能会有多个线程并行的修改RememberedSet,这样就需要花费额外的时间来解决多线程同步问题。而这种更新引用是频繁的,所以这种额外时间是无法忍受的。 2、Dirty Card Queue 这个队列有白、绿、黄、红四个颜色,表示应用线程往这个队列放任务的状态。 White 表示没有应用线程往队列里放任务,什么事都不用干。 Green 此时Refinement线程开始被激活,开始更新RS。-XX:G1ConcRefinementGreenZone=N Yellow 此时全部的Refinement线程都被激活,来更新RS。-XX:G1ConcRefinementYellowZone=N Red 这个时候,应用线程也开始参与排空队列的工作。-XX:G1ConcRefinementRedZone=N 四、GC算法的过程 1、Fully young GC GC的过程 (1)STW 此时会暂停所有堆中的对象,将部分Region拷贝到指定区域。 (2)构建Collection Set fully young GC就是选取所有的Eden和Survivor。 (3)扫描GC Roots (4)更新RememberedSet 排空Dirty Card Queue (5)Process RS 根据RS找到要GC的对象被哪些对象引用了。 (6)对象拷贝 survivor区域对象的调整。 (7)Reference Processing 额外会做的事 G1记录每个阶段的时间,用于后期自动调优。比如说会记录Eden、Survivor的数量和GC时间,后期会根据我们之前设定的暂停目标来自动调整Region数量。 但是我们设置暂停目标越短,年轻代的Region数量就越少。但这可能会导致Fully young GC频繁发生。 2、Old GC 当堆用量达到一定程度时,就会触发old GC。可以通过以下参数进行设置: -XX:InitatingHeapOccpancyPercent=45 old GC有一个很大特点就是并发进行的。但它是如何在堆中不断变化的情况下,确定哪些是要清理的垃圾对象呢? 三色标记算法 这种算法实现了在不暂停应用线程的情况下进行并发标记,标记过程过如下: (1)将GC Root对象记录为黑色,其直接引用对象记录为灰色,并将这些灰色对象放入一个队列中 (2)从队列取出对象,将其标为黑色,将其引用对象记录为灰色,再放入队列中 (3)直到队列中无对象为止 三色标记算法的缺点:Lost Object Problem 三色标记算法并没有完全将所有的活对象都标记出来,这就是Lost Object Problem问题。比如说: (1)刚开始时 (2)在即将描述将C标为灰色的一刹那 此时,C依然是活对象,但是已经无法将其标记了。 (3)结果 Lost Object Problem的解决 这种解决办法还是通过Write barrier技术来解决。当B.c=null,也就是C指针被删除时,G1还是被认为活对象。 那如果C是新生对象呢?这是老年代GC Old GC过程 (1)STW 老年代GC会在这个时候,进行一次Fully young GC (2)恢复应用线程 (3)使用三色标记算法并发标记(init marking) (4)STW 这时候会有一个Remark阶段,主要是解决SATB、Reference processing 还会有一个Cleanup阶段,用于回收全为空的区 (5)恢复应用线程 3、Mixed GC 我们直到CMS最大的缺点就是无法进行压缩操作,而G1就通过Mixed GC解决了这个问题。 Mixed GC没有固定触发条件,他是根据Fully young GC收集的信息和我们配置的时间来决定,是否触发Mixed GC。它会根据暂停目标,来优先选择垃圾最多的Old Region来执行。 Mixed GC会选择若干个Region进行,默认是选择1/8的Old Region、Eden Region、Survivor Region。 Mixed GC的过程跟Fully young GC的过程相同,都是:STW、Parallel、Copying。 原博客地址

/template/Home/Zkeys/PC/Static