堆内存的划分 分为三个部分(以下名词表示同一个区): 新生区、新生代、年轻代 养老区、老年区、老年代 永久区、永久代 划分区域的目的 唯一目的就是优化GC性能。 如果没有分代
堆内存的划分分为三个部分(以下名词表示同一个区):
划分区域的目的
如果没有分代,我们所有的对象都放在一块,GC的时候我们需要对堆的所有区域进行扫描。而很多的对象都是“朝生夕死”的,如果把创建的新的对象都放在某一地方,当GC的时候就先把“朝生夕死”对象的区域进行回收,这样就会腾出很多大的空间来。 一、新生区的垃圾回收机制
1.开始时创建的对象都是分配在Eden区域中,当Eden区快满了,就会触发垃圾回收Minor GC(使用复制算法进行垃圾回收) 2.Minor GC处理后,首先会把Eden区中还存活着的对象一次性转入其中一块空闲着的Survivor区。然后清空Eden区,之后创建的对象就继续放入Eden区中了,直至下次Eden又被填满。 3.Eden再次被填满时,就会再次出发Minor GC,清理后(Minor会清理Eden区和Survivor区的内存),Eden区和存在对象的Survivor区(此时的from区)中存活的对象转移到另一块空着的Survivor区中(此时的to区),并清空Eden区和之前存在对象的Survivor区(此时变为to区了,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。)
二、什么时候进入老年区呢?1 经历15次GC后进入老年区默认情况下,如果新生区中的某个对象经历了15次GC后,还是没有被回收掉,那么它就会被转入老年区。 2 动态对象年龄判断这种方法不用等到经历GC15次。 例:假设Survivor0区中的两个对象都经历的3次GC(年龄3),而且这两个对象总大小50M,超过了Survivor0区内存大小的一半。那么此时Survivor0区中年龄大于等于3岁的对象就都要被全部转移到老年区。 3 大对象直接进入老年代有一个JVM参数"-XX:PretenureSizeThreshold",默认值是0,表示任何情况都先把对象分配给Eden区。 4 Minor GC后存活的对象太多无法放入Survivor区了Minor GC后存活的对象太多,导致Survivor区放不下了,此时就会将所有的对象直接转移到老年区中。 三、老年区空间分配担保原则执行每一次Minor GC前,JVM都先检查一下老年区可用的内存空间是否大于新生区所有对象的总大小。 原因:极端情况下,Minor GC后,新生代中所有的对象都活了下来,那就会把所有新生代中的对象放入老年区中。
三种情况递进理解: 1.如果Minor GC后,存活的对象<Survivor区大小,直接进入Survivor区即可; 2.如果Minor GC后,存活的对象>Survivor区大小,但<老年区可用内存,直接进入老年区; 3.若Minor GC后,此时老年区都放不下这些存活的对象了,就会触发Full GC; 四、老年区垃圾回收算法
【原理】 一开始对象都是任意分布的,在经历完垃圾回收之后,就会标记出哪些是存活对象,哪些是垃圾对象,然后就会把这些存活的对象在内存中进行整理移动,尽量都挪到一边去靠在一起,然后再把垃圾对象进行清除,这样做的好处就是避免了垃圾回收后产生的大片内存碎片。 【缺点】 较为耗时,比复制算法慢10倍; 所以如果系统频繁出现Full GC,会严重影响系统性能,出现卡顿。所以JVM优化的一大问题就是减少Full GC频率。 五、垃圾回收器新生区和老年区进行垃圾回收时是通过不同的垃圾回收器进行回收的 Seral 和 Seral Old垃圾回收器
ParNew和CMS垃圾回收器
G1垃圾回收器 统一收集新生区和老年区,采用更加优秀的算法机制。 |
2021-06-05
2021-05-27
2021-05-26
2021-06-05
2021-05-16