前言
个人学识浅薄,关于JVM相关知识尚在学习阶段,博客内容属于个人从各渠道学习理解总结而来,定存在错误,遗漏的地方。尤其是流程图尚存在不完善之处,个人已更正几版。欢迎各位看官不吝赐教,求同存异,共同学习,共同进步,谢谢!
另重要的东西说三遍:要看流程图,要看流程图,要看流程图!
GC执行流程图
1. MinorGC触发的时机(参考流程理解,姿势更加哦)
1.1 老年代最大可用连续空间大于新生代所有对象的总和
因为有老年代在给新生代GC做兜底(空间担保机制),哪怕新生代中的对象全部存活,只要老年代中最大可用连续空间大于新生代中所有对象的总和,老年代都可以放的下,所以此时新生代可以放心的GC,即进行MinorGc,又称YoungGc.
1.2 老年代最大可用连续空间大于新生代历次晋升到老年代的平均大小
当老年代最大可用连续空间小于新生代所有对象的总和且老年代最大可用连续空间大于新生代历次晋升到老年代的平均大小时,虽有可能发生极端事件:新生代所有的对象都存活,但毕竟是极小概率事件。有大于新生代历次晋升到老年代的平均大小条件的保证大概率事件上老年代是可以放的下的,真的放不下了就会发生FullGc了.
2. 触发FullGc时机
2.1 老年代最大可用连续空间小于新生代历次晋升到老年代的平均大小
当老年代最大可用连续空间小于新生代历次晋升到老年代的平均大小时,也就意味着大概率事件老年代无法满足本次新生代的晋升所需的空间,这时候就要进行FullGc,对新生代,老年代,元空间进行垃圾回收。极端情况,经过FullGc后,老年代仍然有大量对象存活,空间仍无法满足需求,这时如果老年代没有达到(堆最大空间-Xmx)- (新生代空间-Xmn)设置的值,那么就会进行扩容。当然一般情况,我们出于避免扩容所带来的效率影响,会将堆最大空间-Xmx和堆最小空间-Xms设置成一样。但是如果老年代已达到最大值时,那么就会发生outOfMemory即OOM异常。
2.2 老年代最大可用连续空间大于新生代历次晋升到老年代的平均大小但是MinorGC后存活的对象大于老年代最大可用连续空间
当老年代最大可用连续空间大于新生代历史晋升到老年的平均大小时,也就意味着大概率事件老年代可以存放的下新生代经过MinorGc后的存活的对象。但是如果存活下来的新生代对象大于servivor区了,咋办?此时JVM又会进行检查,检查老年代最大可用连续空间是否大于这些存活下来的新生代对象,如果大于即老年代放的下,存活对象直接全部进入到老年代中。但是如果老年代放不下了,此时就会触发FullGc。
关于MinorGc以及FullGc的一些思考
当新生代Eden空间不足但老年代空间充足(大概率事件放的下新生代经过MinorGc存活的对象)的情况下,优先进行MinorGc。而当老年代空间不充足(大概率事件放不下新生代经过MinorGc存活的对象以及确定老年空间不足)的情况下,才会进行FullGc。毕竟FullGc比MinorGc更加耗时,STW时间更长(跟回收算法,垃圾回收器有关)。所以,JVM在设计回收机制时更加偏向于优先进行MinorGc,最后实在没辙了,开始放大招了(FullGc),其实也是无奈之举。故JVM优化时,要使得比较少的对象进入老年代,减少FullGc发生的次数。
3. JVM内存分配
3.1 大多数情况下,对象优先分配到Eden区
3.2 大对象直接进入老年代
3.3 存活时间久的对象进入老年代
3.4 动态对象年龄判断机制
3.5 MinorGc后存活的对象Servivor区放不下也直接进入老年代
<待续>