-XX:+UseG1GC-XX:InitiatingHeapOccupancyPercent=N这个参数,默认情况下,参数为45-XX:G1MixedGCCountTarget=N该参数可以控制每次混合循环回收的Old分区的数量。该参数默认值为8;-XX:G1HeapRegionSize=N;只要对象大小>=1/2区域,那么这个对象就会被JVM标记为Humongous对象。每个巨型对象都是一组连续的区域,分配在老年代。例如:region为1m,objectsize为600KB,那么剩下的空间(1024kb-600kb)就会变成碎片,不再参与分配。需要避免HumongouObj的生成,避免大对象的加载。、-XX:MaxGCPauseMillis=200–设置目标最大暂停时间。这是一个理想化的目标,JVM会尽量去完成它-XX:G1ReservePercent=n,默认是10G1会预留部分内存来制造一个假的天花板,防止to-sapce耗尽。杨gc:当新生代空间不够时mixedgc:当老年代大小占整个堆大小的百分比达到阈值时,混合gc.fullgc:G1会在以下场景触发FullGC,以及会在log中记录-space-exhaustedandEvacuationFailure:1.从新生代分区复制存活对象时,找不到可用的空闲分区。2.从老年代分区转移存活对象时,找不到可用的空闲分区。3.在oldgeneration分配hugeobjects时无法在时代找到足够的连续分区。MetadataGCThreshold:元数据空间不足也会触发fullgc。RememberedSet:当虚拟机发现程序正在写入Reference类型的数据时,会生成一个WriteBarrier暂时中断写入操作,并检查Reference所引用的对象是否在不同的Region中。如果是,则通过CardTable将相关引用信息记录到引用对象所属Region的RememberedSet中。RSet中记录了引用——即其他Region对本Region所有对象的所有引用,即谁引用了我的对象。G1GC每次都会对年轻代进行一次全面收集(fullscan)。因此young->old和young->young不需要记录在RSet中。对于old->young和old->old的代际对象引用,需要一个RSet。对于G1进行YGC时的跨代引用,以及进行MixedGC时的old跨区域引用,只需要扫描这个RegionRSet中记录的region,寻找引用脏卡区域的对象,然后按照同样的判断是否存活的方法,进而判断本分区对象的存活情况。无需为PLAB(提升本地分配缓冲区)扫描整个堆。每个线程在生存空间和旧空间中都有一个PLAB。升级时可以避免多线程竞争,从而提高效率。一个CSet(CollectionSet)代表了一个目标分区的列表,这些分区在每次GC暂停时被回收。在任何一次收集暂停期间,CSet的所有分区都会被释放,内部存活的对象将转移到分配的空闲分区中。所以不管是新生代收集还是混合收集,工作机制都是一样的。新生代收集CSet只容纳新生代分区,而混合收集使用启发式算法,在老年代候选回收分区中筛选出回收收益最高的分区加入到CSet中。可以通过活动阈值-XX:G1MixedGCLiveThresholdPercent(默认85%)设置候选老年代分区的CSet准入条件,拦截那些回收成本巨大的对象;同时,每个混合集合可以包含候选老年代分区,可以根据CSet占堆总大小的比例设置数量上限-XX:G1OldCSetRegionThresholdPercent(默认10%)。G1的集合是基于CSet的操作。新生代收集和混合收集没有明显区别。最大的区别在于两个集合的触发条件。新生代垃圾回收只会回收Eden区和Survivor区。YGC期间,首先G1停止应用程序的执行(Stop-The-World),G1创建一个集合集(CollectionSet)。集合集是指需要回收的内存段的集合。新生代收集过程的collectionset包含了Eden区和Survivor区所有内存段的youngGeneration。然后按如下方式启动回收过程:在第一阶段,扫描根。根是指静态变量指向的对象,正在执行的方法调用链上的局部变量等。RSet记录的以下引用和外部引用,作为扫描存活对象的入口。第二阶段更新RSet。处理脏卡队列中的卡(见备注)并更新RSet。这个阶段完成后,RSet就可以准确反映出老年代对其所在内存段中对象的引用。备注:对于应用程序的引用赋值语句object.field=object,JVM会在dirtycardqueue中入队一个保存了object引用信息的card前后进行特殊操作。当年轻代回收时,G1会处理DirtyCardQueue中的所有卡片,更新RSet,保证RSet实时准确反映引用关系。那为什么不直接在引用赋值语句处更新RSet呢?这是为了性能需求。RSet的处理需要线程同步,开销会很大,使用队列性能会好很多。第三阶段是处理RSet。识别老年代对象指向的Eden中的对象。Eden中被指向的这些对象被认为是幸存对象。第四阶段,复制对象。这个阶段会遍历对象树,将Eden区内存段中存活的对象复制到Survivor区的空内存段中。如果Survivor区的内存段中存活对象的年龄没有达到阈值,则年龄加1。复制到Old区的一个空内存段。如果Survivor空间不够用,Eden空间的部分数据会直接提升到老年代空间。第五阶段是处理参考文献。处理Soft、Weak、Phantom、Final、JNIWeak和其他引用。最终Eden空间的数据为空,GC停止工作,目标内存中的对象被连续存储,没有碎片,所以复制过程可以达到内存组织的效果,减少碎片。G1回收过程2:并发标记过程初始标记阶段:标记从根节点直接可达的对象。这个阶段是STW,会触发新生代GC。RootRegionScanning:G1GC扫描survivorregion中直接可达的oldageregion中的对象,并标记被引用的对象。这个过程必须在youngGC之前完成。ConcurrentMarking:并发标记是在整个堆上进行的(与应用程序并发执行),这个过程可能会被youngGC打断。在并发标记阶段,如果发现区域对象中的所有对象都是垃圾,则立即回收该区域。同时,在并发标记过程中,计算每个区域的对象存活率(区域内存活对象的比例)。备注(Remark):随着应用的继续,需要修改上次的评分结果。它来自STW。G1采用了一种比CMS更快的初始快照方法:snapshot-at-the-beginning(SATB)。独占清理(cleanup,STW):计算每个区域存活对象的比例和GC回收,并进行排序,找出可以混合回收的区域。为下一阶段铺路。它来自STW。并发清理阶段:识别并清理完全空闲的区域。G1回收过程三:混合回收当越来越多的对象被提升到老区域时,为了避免堆内存耗尽,虚拟机触发混合垃圾收集器,即MixedGC。这个算法不是OldGC,除了回收整个YoungRegion外,还会回收一部分OldRegion。这里注意:是部分老年,不是全部老年。你可以选择收集哪些OldRegions,这样你就可以控制垃圾收集的耗时。另请注意,混合GC不是FullGC。并发标记结束后,回收老年代中100%垃圾的内存段,计算部分垃圾的内存段。默认情况下,老年代中的这些内存段会被回收8次(可以通过-XX:G1MixedGCCountTarget设置)。混合回收的集合集包括八分之一老年代的内存段、Eden区的内存段、Survivor区的内存段。混合回收算法和新生代回收算法完全一样,只是将老年代的内存段加入到回收集合中。详见上文新生代回收流程。由于老年代内存段默认回收8次,G1会优先回收垃圾较多的内存段。垃圾占内存段的比例越高,优先收集的垃圾就越多。并且有一个阈值会决定内存段是否被回收。-XX:G1MixedGCLiveThresholdPercent,默认为65%,表示只有内存段占比达到65%时才会回收垃圾。如果垃圾比例太低,说明存活对象比例高,需要更多的时间来复制。混合回收不必进行8次。有一个阈值-XX:G1HeapWastePercent,默认值为10%,意思是允许整个堆内存的10%被浪费掉,也就是说如果发现堆内存中可回收垃圾的比例是低于10%,不再进行混合回收。因为GC花费的时间很多,但回收的内存很少。g1STABtopreventmissinglabels可以简单理解为,当灰色对象取消对白色对象的引用时,则白色对象变灰。这样做的坏处是白色对象可能没有黑色对象引用它,但它仍然是灰色的,这会导致它和它的引用被垃圾回收,但是这次GC幸免于难,这就是所谓漂浮垃圾。其实这样更能容忍,只要让它存活更多只是GC,浪费了一点空间,但是比增量更新会节省更多的时间。SATB也有副作用。如果修改引用的白色对象是要回收的垃圾,这个标记会让它逃过GC,就是浮点垃圾。因为SATB的精度比较低,所以产生的floatgarbage会比较多。https://www.jianshu.com/p/989...https://www.jianshu.com/p/ac1...https://renfufei.blog.csdn.ne...https://www.cnblogs.com/junio...
