1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 游戏引擎jvm频繁young gc问题分析

游戏引擎jvm频繁young gc问题分析

时间:2020-10-01 17:17:35

相关推荐

游戏引擎jvm频繁young gc问题分析

问题背景:

阿里云vpc部署的游戏引擎服务端集群中有一个节点相对于其他节点来说ygc的次数远远超出正常情况,不过fgc次数是正常的。一般来说出现这种问题,首先要看下jvm gc图,后来发现基本都是par new复制标记算法,cms未出现过。

#查看java进程pidjpc -v#根据pid 来查看s0 s1 e 区 的占用情况jstat -gcutil 9777S0C S1C S0U S1UEC EU OC OU MCMU CCSC CCSU YGCYGCT FGC FGCTGCT1536.0 1536.0 0.0 993.8 23040.0 15203.0 250880.0 185933.1 138688.0 131884.0 16576.0 15356.4 23347 162.034 113.179 165.214

jvm基本结构

JVM内存结构主要有三大块:堆内存、方法区和栈。堆内存是JVM中最大的一块,由新生代和老年代组成,而新生代内存又被分成三部分,Eden空间、From Survivor空间、To Survivor空间,默认情况下新生代按照 8:1:1 的比例来分配;方法区存储类信息、常量、静态变量等数据,是线程共享的区域,为与Java堆区分,方法区还有一个别名Non-Heap(非堆);栈又分为java虚拟机栈和本地方法栈,主要用于方法的执行,java GC 主要在堆中进行。

新生代

eden

eden也叫做伊甸园,所有的堆对象新生的地方,所以才叫伊甸园。特点就是来的也快,走得也快,大白话就是来也匆匆去也匆匆。按照java项目的特点来说,基本上大部分对象都是朝生夕死(相比来说 人类太幸福了)。当jvm判定这个对象要死亡的时候,GC就会来回收这部分空间,并将对象回收掉。

那么有人肯定会问,由什么来判断谁要去世,那么这个时候就需要比较隆重的介绍在新生代内部的minor gc。经过一次minor gc之后,eden区的对象就年长一岁,前提是还没死亡的。那么便会将这些对象从eden区搬运到s0区(前提是s0区有足够空间容纳 不然人家自己都住不下去了 也不会昂让你来)。

s0(from survivor)

好了 大家发现eden区的那群难民已经成功着陆到了s0区了,我们可以叫这个地方幸存区0。本来这堆难兄难弟觉得自己安全了,没想到啊,gc的大刀还是挥到了自己的头上。以后在s0区每熬过一次minor gc,对象的年龄就大一岁。

s1(to survivor)

当然在par new垃圾回收复制标记算法的清除下,对象的gc基本上是在s0 s1反复横跳。直到对象的年龄到了15岁(我们16岁成年 他们似乎早点)。这个成年时间其实我们可以设置的,设置的参数如下:

#默认是15 如果有其他的需求的话可以设置的偏大或者偏小-XX:MaxTenuringThreshold

老年代

老年代会出现full gc的垃圾收集动作,所采用的算法是"标记-清除"算法。同样的fgc涉及的对象及空间更为广泛和多,所以fgc的次数比minor gc更少,时间更长一点。但是标记-清除算法同样也会带来问题"内存碎片",在不断地标记清除过程中,会出现不连续的内存空间。导致较大的对象没办法进入到old区,不能把old区充分的利用。

gc算法

partial GC

没有涉及到整个堆空间的gc收集算法,包括以下这三种:

Young GC:只收集 young gen 的GCOld GC:只收集 old ge n的GC。只有CMS的 concurrent collection 是这个模式Mixed GC:收集整个 young gen 以及部分 old gen 的GC。只有G1有这个模式

Full GC

收集整个堆空间的算法,包括年轻代 老年代 元空间。

两者之间的区别

partial gc是因为局部空间无法做再分配,比如幸存区或者伊甸园空间不够了,会触发partial gc。

老年代空间到达设定的阈值(old GC)一般来说不同的jdk版本所设置的阈值会有所改变。

Par New算法(复制清除算法)

ParNew回收器 是 Serial 垃圾回收器的多线程版。采用的是复制清除算法。简单来说就是将内存分为两块(from 和 to)相等的大小,扫描一块内存(from)中所有存活的对象,复制到另外一个内存空间(to),之后再清除第一块内存(from)。

CMS(标记-清除算法)

并发执行的标记-清除算法

为什么会频繁young gc

现在再回到刚刚的问题上来,为啥会频繁的出现ygc,怎么看出的频繁的ygc,首先阿里云的部署采用的是edas部署,可以监控到jvm每十五秒的运行情况。

图一是ygc频繁出现的节点,gc的示意图:

图二是ygc较为正常的其他节点,gc的示意图:

通过对比发现,节点一的gc次数明显偏多,那么出现这种情况,我们可以从两个思路来分析这个问题,第一点:有没有二方引用的客户端或者其他服务在内存中不断地产生新的对象,导致空间一直处于快要突破的状态,第二点:eden区的大小需要观测一下。

登录到节点一使用jps jstat等命令在线上服务器查看一下对应的java进程情况

jps -v#整个堆空间的占用情况jstat -gcutil 9777 1000#新生代jvm占用情况jstat -gcnewcapacity 9777 1000

最后发现是因为节点1 是灰度发布节点,内存以及其他的配置分配较小导致的。不过在线上出问题的时候也是需要一步步的找到线索,为以后的其他类似情况打下基础。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。