文本已收录至个人GitHub仓库,欢迎Star:github.com/bin39232820…
种一棵树最好的时间是十年前,其次是如今
我知道不少人不玩qq了,可是怀旧一下,欢迎加入六脉神剑Java菜鸟学习群,群聊号码:549684836 鼓励你们在技术的路上写博客git
前面的章节github
上面一篇文章你们其实能够搞懂G1的动态内存管理策略,它会根据状况动态的把Regiuon分配给 新生代,Eden,Survivor,老年代和大对象,可是新生代和老年代有一个各自最大的占比,而后在新生代Eden满的时候,触发新生代垃圾回收。算法
新生代的垃圾回收仍是采用了复制算法,只不过会考虑预设的GC停顿时间,保证垃圾回收的停顿时间不难超过设置的时间,所以会挑选一些Region来进行垃圾回收。并发
而后跟以前说的同样,若是一些对象在新生代熬过拉框必定次数的GC,或者触发了动态年龄断定规则,则会进入老年代工具
而大对象则是进入单独的Regin,再也不进入老年代布局
因此实际上在G1中,仍是会存在新生代的对象会由于各类状况进入老年代post
G1 有个参数 是-XX:InitiatingHeapOccupancyPercent 它的默认值是45%性能
意思是说 若是老年代占了 堆内存的45%的Region的时候,此时就会触发混合回收阶段 以下图学习
首先会触发一个 初始标记的操做,这个过程须要 Stop the world 的,可是这个过程很快测试
以下图,先中止系统程序的运行,而后对各个线程栈内存中的局部变量表明GC Roots,以及方法区表明静态变量的Roots,进行扫描,标记出他们直接引用对象。
接下来就会进入到 并发标记的阶段,这个阶段会容许系统程序继续运行,同时进行GC Root追踪,以下图所示
这个并发标记阶段仍是很耗时的,由于要追踪所有的存活对象
可是这个阶段是能够跟系统程序并发进行的,因此对系统程序的影响不太大
并且JVM会对并发标记阶段对象作出一些记录,好比哪一个对象新建了,哪一个对象失去引用了,等等
接着下一个阶段就是 最终标记阶段,这个阶段也会进入Stop the world ,系统程序是禁止运行的,可是会根据并发标记记录那些 对象修改,最终标记哪些对象存活,以下图所示
最后一个阶段 是混合回收阶段,这个阶段会计算老年代每一个Region中的存活对象数量,存活对象占比,还有执行垃圾回收的预期性能和效率。
接着会中止系统程序,而后尽心尽力尽快进行回收,此时会选择部分Region进行回收,由于必须让垃圾回收的停顿时间控制在咱们指定的范围内。
好比说 老年代此时有1000Region都满了,可是由于设置的时间,只能停顿200ms,不那么我只能回收800个,那么就会只回收800个Region,把GC的时间控制在咱们指定的范围以内,以下图
这是一个百万级注册用户的在线教育平台,主要目标用户群体是几岁到十几岁的孩子,注册用户大概是几百万的规模,日活跃规模大概在几十万。
系统的业务流程其实也不复杂,并且咱们能够排除掉一些选课,排课,浏览课程详情这些低频行为。
为啥呢?由于它不是一个电商平台,不是说每一个人进去都会去浏览课程详情, 因此 通常的业务流程就是,有人进来浏览一下,考虑一段时间,而后买拉课程,因此它的高频行为是什么呢?我想了一下,应该是上课
也就是说,孩子们白天要在学校上课,通常也是晚上 8 9点的样子,是这个平台最活跃的时候,还有就是周末也是最活跃的时候,
因此晚上二三个小时的时间段,将会是平台的高峰期,并且白天几乎没有什么流量,可能90%的流量读在晚上,以下图所示
接着咱们来明确一下,这样的一个系统,孩子们在上课的时候主要高频的使用哪些功能呢
其实很是的简单,如今若是你们家里有孩子,平时对一些在线教育App有必定的了解的话,应该知道如今在线App都会主打互动环节
给你们举个例子,好比说给五六岁的孩子上的幼儿园英语课,你们以为还会像之前同样吗,机械的跟读嘛
那确定不是了,如今尤其强调的是在欢快的愉快的游戏中进行教学,让孩子们快乐的学习英语,数学之类学科的知识
因此说 在那几十万用户 晚上最高峰的时间使用系统上课的时候,尤其核心的业务流程就是大量的游戏互动环节
也就是说,这个游戏互动功能,必定会承担用户高频点击,大量的互动点击
好比在完成什么任务的时候必须点击不少的按钮,频繁的进行互动,而后系统后台须要大量的接收大量的互动请求,并记录用户互动的结果,
系统得记录下来用户完成了多少个任务,做对了几个,作错了几个。
如今咱们开始来分析一下这个系统运行时候对内存使用的一个压力
其实核心点就是搞明白晚上二三个小时高峰期内,每秒钟会有多少请求,每一个请求会连带产生多少对象,占用多少内存,每一个请求处理多长时间。
首先咱们来分析一下晚上高峰期内几十万用户同时在线使用平台,每秒钟会产生多少请求?
咱们能够大体来估算一下,好比说晚上3小时高峰期内总共60万活跃用户,平均每一个用户大概会使用1小时左右来上课,一个小时内会进行60次互动操做
那么20W活跃用户由于须要大量的互动操做,因此大体能够认为是每分钟进行1次互动操做,一小时内会进行60次互动操做
那么20万用户在1小时内会进行1200万次互动操做,平均每秒大概是3000次左右的互动操做,这个是一个很合理的数字
那么每秒要承载3000并发请求,根据经验来看 通常核心系统须要部署5台 4核8G的机器来抗住是差很少的,每台机器能抗住600请求,这个压力能够接受,通常不会致使宕机问题。
一次互动请求不会有太复杂的对象,他主要是记录一些用户互动过程的,可能会跟一些积分类的东西有关联
因此大体估算一下,一次互动请求大体会连带建立几个对象,占多大的内存,好比咱们就认为是5kb吧那么一秒600请求会占用3MB左右的内存
接着咱们来看看G1垃圾回收器的默认内存布局,咱们采用4核8G的机器来部署系统,而后每台机器每秒会有600个请求会占用3Mb左右的内存空间。
那么假设咱们对机器上的JVM,分配4G给堆内存,其中新生代默认初始占比5%,最大占比60%,每一个Java线程的栈内存为1MB,元数据区域的内存为256M,此时的JVM参数以下
-XX:G1NewSizePercent 参数是用来设置新生代初始占比的,不用设置,维持默认值5%就能够了
-XX:G1MaxNewSizePercent 参数是用来设置新生代最大占比的,也不用设置 维持默认的60%就能够了
此时堆内存共4G,那么此时会除以2048,计算每一个Region的大小,此时每一个Region的大小就是2MB,刚开始新生代就占5%的Region,能够认为新生代就只有100个Region,有200MB的内存空间,以下图所示。
在G1垃圾回收器中有一个相当重要的参数会影响到GC的表现,就是 -XX:MaxGCPauseMills,它的默认值是200毫秒
也就是咱们每次触发GC的时候致使的系统停顿时间 Stop the world 不要超过200ms,避免系统由于GC长时间卡死。
这个参数咱们能够先保持一个默认值,继续往下分析看看,不着急忙下结论
有一个问题,就是系统运行起来以后,会不停的在新生代的Eden区域分配对象,按照以前的推算是每秒分配3MB的对象,以下图
那何时Eden的区域会不够呢?
前面咱们说过 -XX:G1MAXNEWSIZE参数规定了新生代最大的堆内存空间
那么难道必须得随着系统运行一直给新生代分配更多得Region,直到新生代占据了60%以后,再进行GC?
G1确定不是这样玩的
咱们假设G1回收300Region须要 200ms
那么颇有可能系统运行时,G1呈现出现以下的运行效果
首先,随着系统运行,每秒建立3MB的对象,大概1分钟左右就会塞满100个Region,以下图所示
此时极可能G1会以为 ,要是我如今就触发GC,那么回收区区200MB 只须要大概几十ms,最多就让系统中止几十ms而已,跟个人主人设定的参数200Ms还相差很远。
若是如今gc, 那么每分钟都要GC会不会太频繁了,好像没有这个必要
因此还不如给新生代先增长一些Region,而后让系统继续运行再新生代Region中分配对象好了,这样就不用过于频繁触发新生代gc了,此时如图所示
而后系统继续进行,一直到可能300个Region都占满了,此时经过计算发现回收300个Region大概须要200ms,那么可能这个时候就会触发一次新生代gc了
G1是很是灵活的,它会根据你设置的时间 给新生代不停的分配更多Region
而后到必定程度,感受差很少了,就会触发新生代gc,保证新生代Gc的时候致使的系统停顿时间再你预设的范围内
其实就是优化-XX:MaxGCPauseMills参数
若是这个参数设置小了 ,那么说明每次gc的停顿时间很短,可是很频繁
若是这个参数设置大了 停顿的时间就会很是长,
因此这个参数到底如何设置,须要结合工具来测试,来达到一个合理的值
其实也是核ParNew +CMS 控制没必要要的对象进入老年代就行了,也是-XX:MaxGCPauseMills这个参数,
你们能够想象一下 若是这个参数很大,那么通过新生代的gc后,就会致使Survivor区域放不下那么多的对象,那么这些对象就会进入老年代了
或者是由于动态年龄判断进入老年代了,因此说仍是设置这个参数
其实也就是把G1简单的说了一下,后面还有具体的干货
由于博主也是一个开发萌新 我也是一边学一边写 我有个目标就是一周 二到三篇 但愿能坚持个一年吧 但愿各位大佬多提意见,让我多学习,一块儿进步。
好了各位,以上就是这篇文章的所有内容了,能看到这里的人呀,都是真粉。
创做不易,各位的支持和承认,就是我创做的最大动力,咱们下篇文章见
六脉神剑 | 文 【原创】若是本篇博客有任何错误,请批评指教,不胜感激 !