6、JVM分代模型--老年代 的垃圾回收

老年代采用的是什么垃圾回收器算法?

老年代中的对象存活时间比较久,每次垃圾回收之后,存活对象比较多,而需要回收的垃圾对象比较少,所以适合采用标记-清除、标记-整理算法。无论是标记-清除还是标记-整理,都有一个阶段是清除垃圾对象,垃圾对象越少则执行效率越高。

对象是如何进入老年代的?

对象年龄够了之后:

前面讲过对象分配在新生代中之后,随着新生代的Eden区满了之后会进行新生代的垃圾回收,也就是Young GC,然后存活对象便流入Survivor1区,然后在Survivor1和Survivor2区中流转,每次Young GC之后存活的对象的年龄就增加1岁,默认当对象的年龄到15岁时,便可以进入老年代了。而具体是多少岁可以进入老年代,可以通过设置参数:-XX:MaxTenuringThreshold来设置。

动态对象年龄判断:

动态对象年龄判断就是说,年龄1+年龄2+…年龄n的所有对象占用的总内存超过了Survivor区的50%,此时就会把年龄n以上的对象都放入老年代。

其实就是说Young GC过后,存活的对象要放入其中一个Survivor区时,判断一下存活对象总和是否大于Survivor区的大小的50%,如果大于了,那么就找到年龄1的所有对象,看看大于还是小于Survivor的50%,如果是小于,就再加上年龄2的所有对象,再看看是大于还是小于Survivor的50%,一次类推,找到第一个大于Survivor的50%的那个年龄n,然后把所有年龄大于n的对象都放入老年代。

这个规则的意义在于:对于那些可能长期存活的对象来说,就尽早进入老年代,不用非要得到15岁之后,尤其是在Survivor区内存有压力的情况下。

大对象直接进入老年代:

如果跑程序的过程中创建了一个“大对象”,那么就不用经过新生代了,直接进入老年代。具体大于多少是“大对象”呢?可以通过参数: -XX:PretenureSizeThreshold来设置,单位为字节。

这样规则的意义在于:避免了大对象进入新生代,然后在Young GC过程中来回复制,降低复制效率。

老年代的空间分配担保机制:

如果Young GC之后,存活的对象太多,Survivor区放不下了,此时怎么办呢?那么此时这些存活对象会被放入老年代中去,也就是说由老年代进行空间分配担保。但随之而来的一个问题就是:如果老年代也放不下怎么办?JVM垃圾回收有一套详细的老年代空间分配担保机制,接下来我们好好看看:

先补充一下基础知识:老年代的垃圾回收叫Old GC,但是一般情况下,Old GC会伴随着新生代垃圾回收、永久代垃圾回收,所以也可以把老年代的垃圾回收叫做:Full GC,也就是全局垃圾回收。

1、Young GC之前是否需要Full GC 让老年代来腾点地方出来?

在执行Young GC之前,做一个判断:老年代可用空间大小是否大于新生代所有对象的总大小?因为极端情况下新生代所有对象全部存活下来也是有可能的。如果大于,那么可以放心地进行Young GC;如果小于,那么会做另外一个判断:查看-XX:HandlePromotionFailure 参数是否设置了?

1.1、如果没有设置,那么此时就会触发一次Full GC,让老年代先腾出一点空间,然后再进行Young GC;

1.2、如果设置了,那么再进行一个判断:老年代的可用内存大小是否大于之前每一次Young GC后进入老年代的对象的平均大小?

1.2.1、如果小于,那么此时还是会先触发一次Full GC,让老年代先腾出一点空间,然后再进行Young GC;

1.2.2、如果大于,那么可以尝试冒一点风险进行Young GC。

2、进行Young GC,Young GC之后有以下几种可能:

        2.1:Young GC过后,剩余的存活对象大小,小于Survivor区大小,那么直接进入Survivor区;

        2.2:Young GC过后,存活对象大小,大于Survivor区大小,但是小于老年代可用内存大小,此时进入老年代即可;

        2.3:Young GC过后,存活对象大小,既大于Survivor区大小,也大于老年代可用内存大小,此时就会发生Handle Promotion Failure的情况,这时便会触发一次Full GC

3、Full GC之后,如果老年代还是没有足够的空间来存放Young GC之后的对象,那么就会发生OOM,也就是内存溢出

老年代什么时候会进行垃圾回收?

在老年代的空间分配担保机制中可以看到,老年代进行垃圾回收的情况有以下一种情况:

1、每次Young GC之前会进行一些判断,看看是否需要老年代先进行一下Full GC;

2、Young GC之后,存活对象Survivor区放不下,老年代也放不下了,那么触发一次Full GC。

老年代什么时候会发生内存溢出?

在老年代的空间分配担保机制中,我们可以看到,如果是Full GC之后,老年代还是没有足够的空间来存放Young GC之后的对象,那么此时就会发生OOM。

设置参数总结:

-XX:MaxTenuringThreshold:决定了对象多大年龄可以进入老年代

-XX:PretenureSizeThreshold:决定了多大的对象可以进入老年代

-XX:HandlePromotionFailure:是否设置空间分配担保

1、JVM是如何工作的?_jerry_dyy的博客-CSDN博客_jvm是如何运行的

2、JVM的类加载机制_jerry_dyy的博客-CSDN博客

3、JVM内存区域划分_jerry_dyy的博客-CSDN博客_jvm的内存区域划分

4、JVM垃圾回收机制_jerry_dyy的博客-CSDN博客

5、JVM分代模型--新生代 的垃圾回收_jerry_dyy的博客-CSDN博客_jvm新生代划分

6、JVM分代模型--老年代 的垃圾回收_jerry_dyy的博客-CSDN博客

7、常见的垃圾回收器_jerry_dyy的博客-CSDN博客

8、JVM优化简介_jerry_dyy的博客-CSDN博客

9、学会查看GC日志_jerry_dyy的博客-CSDN博客

10、摸清JVM运行状况_jerry_dyy的博客-CSDN博客

11、摸清JVM对象分布_jerry_dyy的博客-CSDN博客

12、OOM简介_jerry_dyy的博客-CSDN博客

13、OOM模拟_jerry_dyy的博客-CSDN博客

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JVM(Java虚拟机)的分代模型是一种内存管理策略,将堆内存划分为不同的代(Generation),包括年轻代(Young Generation)、老年代(Old Generation)和永久代(Permanent Generation,JDK8之后被元空间(Metaspace)取代)。下面是JVM分代模型的执行流程: 1. 初始阶段:当Java应用程序启动时,JVM会为其分配一块初始的堆内存空间。此时,年轻代和老年代都是空的。 2. 对象创建:当Java程序创建对象时,对象会被分配在年轻代的Eden区域。如果Eden区域没有足够的空间来存放新创建的对象,就会触发一次垃圾回收(Minor GC)。 3. Minor GC:在Minor GC中,垃圾回收器会扫描年轻代的Eden区域和Survivor区域,将不再被引用的对象进行回收。存活的对象会被移动到Survivor区域中的一个空闲区域。 4. 对象晋升:当一个对象经过多次Minor GC后仍然存活,它会被晋升到老年代。晋升条件可以根据不同的垃圾回收器而有所不同。 5. Major GC:当老年代空间不足时,会触发一次Major GC(也称为Full GC)。在Major GC中,垃圾回收器会扫描整个堆内存,对不再被引用的对象进行回收。 6. 永久代/元空间:永久代(JDK8之前)或元空间(JDK8及以后)用于存放类的元数据和常量池等信息。当类的元数据不再被使用时,会触发一次永久代/元空间的垃圾回收。 7. 内存分配担保:在进行垃圾回收时,如果老年代的空间不足以存放新创建的对象,JVM会进行一次内存分配担保。即使触发了垃圾回收,也能保证新创建的对象能够顺利分配到老年代。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值