您好,我是湘王,这是我的51CTO博客,欢迎您来,欢迎您再来~
G1替代了ParNew+CMS这对搭档组合,既能实现年轻代的垃圾回收,也能实现老年代的垃圾回收。现在继续来说说它的混合回收问题。
在JVM参数中,有一个设置项-XX:InitiatingHeapOccupancyPercent,它的默认值是45%,也就是-XX:InitiatingHeapOccupancyPercent=45。也就是说,如果老年代空间 ≥ JVM堆内存大小 × 45%,就会触发混合回收。
例如,当JVM有2048个Region,而老年代Region≈1000时,就触发混合回收。
G1的混合回收,也有这么几个步骤:
1、初始标记阶段:Stop the World,仅仅只是标记一下GC Roots直接能应用的对象。
2、并发标记阶段:恢复系统程序运行,同时进行GC Roots追踪所有的存活对象,比较耗时,同时将对象的做出的修改记录下来。
3、最终标记阶段:再次Stop the World,最终标记哪些是存活对象,哪些是垃圾对象。
4、混合回收阶段:先计算老年代中每个Region里面的存活对象数量,占比,GC的预期性能及效率。然后停止系统,全力以赴尽快进行垃圾回收,同时控制GC停顿时间,满足预期目标。
在混合回收阶段,不仅仅回收老年代,也会同时回收年轻代和大对象。从年轻代、老年代、大对象中各自挑选一些Region,在满足性能前提下(允许GC卡顿的时间),回收尽可能多的垃圾对象。
一些常见G1的参数:
l -XX:G1MixedGCCountTarget=8,在一次混合回收过程中,最后一个阶段(混合回收阶段)执行几次回收动作,默认8次;
l -XX:G1HeapWastePercent=5,一旦回收执行完成,发现空闲出来的Region数量达到JVM的5%,就立即停止回收;
l -XX:G1MixedGCLiveThresholdPercent=85,当某个Region的存活对象低于85的时候,这个Region才能进行回收。
而一旦混合回收失败,就会马上执行下面的动作(可以理解为类似于事务回滚):
l 停止系统运行;
l 采用单线程进行标记、清理、压缩和整理;
l 回收垃圾,空闲出一批Region;
l 恢复混合回收过程。
有这么一个G1案例:
l 某百万级注册用户的在线教育平台,DAU≈60万;
l 选课、排课、课程详情都属于低频浏览页面;
l 上课使用频次最高;
l 99%的流量都集中在每天18:00~21:00;
l 会有大量的游戏互动环节,即大量点击事件、请求和结果。
系统压力:
l 3小时60万用户,即每1小时20万用户;
l 每1分钟1次互动,则1小时1用户互动60次;
l 1小时所有用户就有1200万次互动,平均每1秒3333次互动,按3500计算;
l 大致需要7台4C8G机器,平均每1台每1秒扛500次请求;
l 1次请求大概创建10KB对象,500次就是5MB。
G1的默认内存布局:
l JVM4G,使用G1垃圾收集器,栈内存1M,元空间256M,年轻代默认占用5%空间,最大60%;
l 单个Region大小 = 4096M / 2048 = 2M;
l 年轻代占5% = 2048 × 0.05 ≈ 100 × 2M ≈ 200M;
l 年轻代占60% = 2048 × 0.6 ≈ 1228 × 2M ≈ 2456M;
l 200M / 5M/秒 = 40秒,2456M / 5M/秒 = 491秒。
触发年轻代GC的时机:假设G1回收200个Region(≈400M)需要200ms,那么年轻代初始占用的5%内存空间,不到1分钟就会被填满。如果此时触发GC,则会出现:每不到1分钟GC就被触发1次,虽然只有200ms的短暂停顿。所以,与其让GC在200M的年轻代空间里被频繁触发,不如在更大的空间里,减少GC触发的频率。如果此时400个Region都被占满,GC回收一次大概200ms,那么这个性价比显然比回收100个Region高出4倍。
和ParNew和CMS不同,G1更喜欢大内存,分配G1参数时,往往会以GB为单位,而不是MB。所以需要给JVM足够的内存空间,结合压测、日志、内存等工具合理地设置-XX:MaxGCPauseMillis的值。
感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~
标签:10,系统优化,G1,Region,回收,混合,GC,JVM From: https://blog.51cto.com/u_15817148/6138648