JVM FULL GC 的完整过程
对象分配规则
对象优先分配在Eden区,如果Eden区没有足够的空间时,虚拟机执行一次Minor GC。
大对象直接进入老年代(大对象是指需要大量连续内存空间的对象)。这样做的目的是避免在Eden区和两个Survivor区之间发生大量的内存拷贝(新生代采用复制算法收集内存)。
长期存活的对象进入老年代。虚拟机为每个对象定义了一个年龄计数器,如果对象经过了1次Minor GC那么对象会进入Survivor区,之后每经过一次Minor GC那么对象的年龄加1,直到达到阀值对象进入老年区。
动态判断对象的年龄。如果Survivor区中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代。
空间分配担保。每次进行Minor GC时,JVM会计算Survivor区移至老年区的对象的平均大小,如果这个值大于老年区的剩余值大小则进行一次Full GC,如果小于检查HandlePromotionFailure设置,如果true则只进行Monitor GC,如果false则进行Full GC。
full gc 过程
程序初始化,新生代的三个空间均为空
Eden被分配的新对象占满,触发第一次Minor GC,Eden中存活对象被复制到Survivor1中,剩余对象被回收(回收后,Eden为空,Survivor1无碎片地存放所有存活对象,Survivor2为空)
Eden再次被新对象占满,触发第二次Minor GC,此时Eden和Survivor1中的存活对象被复制到Survivor2中,剩余对象被回收(回收后,Eden为空,Survivor1为空,Survivor2无碎片地存放所有存活对象)
如此交替,在执行一定次数的Minor GC后,会通过Full GC将survivor中的存活对象移入老年代。
实战情况
实战有一种情况
从JVM的分配可以看出:
新生代分配:capacity = 628162560 (599.0625MB),Eden Space:capacity = 558432256 (532.5625MB),
老年代分配:capacity = 5744558080 (5478.4375MB)。
从数据分析出:
新生代设计过小,导致新生代频繁gc。
其次,新生代设计过小,导致大对象无法分配,直接分配到老年代。
导致老年代空间占用过大,从而占用整个系统内存空间。
可能导致其他服务内存不足。
从图上看,平均每分钟发生10几次Young GC,只要超过2分钟,大对象在两个survivor之间已经挪动超过MaxTenuringThreshold(默认15)次了,被移动到old generation是意料之中的事情。
回收老年代也不是100%都在卡顿期间,可以先把gc log打出来看看,分析一下程序卡顿的时间,如果影响大到不可接受,可以从多个方面入手优化
加内存,2G不够用4G,4G不够用8G,单机内存很便宜
减小批处理的批次大小,单次控制在30秒或更短时间以内
批处理执行过程中,清除大对象中的部分数据,不要积累到跑完再清
尝试别的gc参数,或者尝试别的gc方法和参数
- 本文标签: JVM fullgc
- 本文链接: http://www.ityoulove.com/article/28
- 版权声明: 本文由崔健宇原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权