1、可以同时回收新生代和老年代。将Java堆内存拆分成多个大小相等的Region,G1页也有新生代和老年代的概念,不过是逻辑上的概念。也就是说,一个Region可以先作为新生代,在被回收后,又作为老年代了
2、设置垃圾回收的预期停顿时间
比如可以指定,G1垃圾回收时,在1小时内由于回收导致的Stop the World不超过1分钟
3、G1会追踪每个Region里的回收价值
即每个Region中的内存大小,回收它们要多少时间,以此在垃圾回收时进行控制,这就是G1的核心设计思路
1、最多有2048个Region
使用-XX:+UseG1GC指定使用G1回收器,此时会自动用堆大小除以2048,Region的大小必须是2的倍数,比如1M、2M、4M
2、刚开始时,默认新生代占比5%,可以通过-XX:G1NewSizePercent来设置比例
在系统运行时,JVM会给新生代增加更多的Region,但默认不会超过60%,可以通过-XX:G1MaxNewSizePercent来设置。而一旦Region进行了垃圾回收,此时新生代的Region数量会减少,这些其实都是动态的
3、新生代依旧有Eden和Survivor的概念 ,-XX:SurvivorRatio=8依旧有效。比如总共有100个Region属于新生代,那么其中就有80个Region属于Eden,20个属于Survivor
4、当新生代的Region占比达到最大值,就会触发young gc,使用复制算法,进入Stop the World状态。选择回收哪些会根据设置的垃圾回收的预期停顿时间来判断
5、对象进入老年代的条件
1)年龄达到指定值
2)动态年龄判断
6、大对象
以前的大对象是直接存入老年代,但G1提供了专门的Region存放大对象,默认一个大对象超过一个Region的50%就放入大对象专门的Region。还可以横跨多个Region来存放。在对新生代,老年代回收时,也会顺带回收大对象Region
1、老年代占据45%的Region,会触发新生代+老年代的混合回收,可以通过-XX:InitiatingHeapOccupanyPercent设置
2、垃圾回收过程
初始标记:Stop the World,标记GC Roots能引用的对象,这个过程速度很快
并发标记:允许系统程序运行,同时从GC Roots追踪所有存活的对象。会对这一阶段对对象做出的一些修改记录起来,比如哪个对象被新建了,哪个对象失去了引用
最终标记:Stop the World,最终标记哪些是存活对象,哪些是垃圾对象
混合回收:Stop the World,计算新生代、老年代、大对象中每个Region存活对象数量,回收时间,然后根据设置的停顿时间,选择回收部分Region。混合回收可以执行多次,即先停止工作,回收掉一些Region,恢复系统运行,再停止工作,回收一些Region
3、一次混合回收,分为几次执行
可以通过-XX:G1MixedGCCountTarget设置,默认8次
4、G1的垃圾回收使用复制算法,不需要像CMS那样,标记清理,再整理内存碎片
核心在于-XX:MaxGCPauseMills的设置,设置的小了,可能GC会很频繁但每次时间很短,设置的大了,可能GC频率很低但每次时间很长,要结合后续大量工具的讲解和实操演练
针对并发量很大的场景,为了提高GC效率,一般使用G1垃圾回收, 或是增大内存