java对象从新生代晋升到老年代的四种方式

晋升的四种方式

  1. 担保机制
  2. 大对象直接进入老年代
  3. 长期存活的对象
  4. 动态年龄判断

1、担保机制

1.1什么是担保机制

     我们都用过花呗借呗、或者信用卡吧? 就是你身上的前不够用的时候,你可以去借信用卡、借花呗、借借呗,但是你必须有个东西来担保,不然人家凭什么借给你?现在来说一般都是用你的信用分来担保的,就像支付宝有芝麻信用分数;还有一些比较大的数目是需要你用车子或房子来抵押的,这就是担保,以确保你不会跑掉;那其实jvm在内存分配的时候也有担保机制,就是你的新生代内存不足的时候,通过担保分配的方式让大对象直接分配到老年代;

1.2 代码示例

接下来,我们运行一组代码测试一下,在运行前需要先加上以下几个jvm的参数

-XX:+PrintGCDetails -verbose:gc -Xms30M -Xmx30M 

参数说明
 * -XX:+PrintGCDetails  程序执行完成后打印内存使用情况
 * -verbose:gc   每次GC后打印日志
 * -Xms30M 初始堆内存
 * -Xmx30M 最大堆内存

java 代码 GcTest.java

public class GcTest {
    
    // 占用1MB空间
    private static final int  _1MD = 1024 * 1024;

    public static void main(String[] args) {
        byte[] bytes = new byte[2 *_1MD];
        byte[] bytes1 = new byte[2 * _1MD];
        byte[] bytes2 = new byte[2 * _1MD];
        byte[] bytes3 = new byte[6 * _1MD];
    }

}

运行后结果如下

由上面的结果可以看到,前面的三个 2M 的对象都分配到了eden (伊甸)区,此时eden区的内存占用已经达到了 99%,第四个占用了6M的对象因为eden区已经放不下了,所以通过了担保机制直接分配到了 ParOldGen (老年代 ) ;

 

2、大对象直接进入老年代

2.1 多大的对象才能称为大对象?

    这个大对象的大小是由用户指定的,使用以下jvm参数进行指定

-XX:PretenureSizeThreshold=对象大小(单位:byte)

这个参数的默认值为0,也就是说,所有的对象创建出来之后默认都是分配到新生代的,当我们指定了大小之后,只要创建出来的对象超过设定值,那么这个对像就会直接晋升到老年代;

需要注意的是:PretenureSizeThreshold参数只对Serial和ParNew两款收集器有效,

2.2 代码示例

首先,加上以下几个参数

-XX:+PrintGCDetails -verbose:gc -Xms30M -Xmx30M  -XX:+UseParNewGC -XX:PretenureSizeThreshold=3145728

参数说明
 * -XX:+PrintGCDetails  程序执行完成后打印内存使用情况
 * -verbose:gc   每次GC后打印日志
 * -Xms30M 初始堆内存
 * -Xmx30M 最大堆内存
 * -XX:+UseParNewGC 使用parNew GC
 * -XX:PretenureSizeThreshold=3145728 对象超过3M时直接晋升到老年代

java代码,这里将对象设为4M,

public class GcTest {

    private static final int  _1MD = 1024 * 1024;

    public static void main(String[] args) {
        byte[] bytes = new byte[4 *_1MD];
    }

}

打印结果

由上面的结果可以看到,因为对象的大小设置为4M,已经超过了参数 PretenureSizeThreshold 设置值3M,所以直接将该对象分配到了老年代;

 

3、长期存活的对象

长期存活的对象进入老年代。在堆中分配内存的对象,其内存布局的对象头中(Header)包含了 GC 分代年龄标记信息。如果对象在 eden 区出生,那么它的 GC 分代年龄会初始值为 1,每熬过一次 Minor GC 而不被回收,这个值就会增加 1 岁。当它的年龄到达一定的数值时(jdk1.7 默认是 15 岁),就会晋升到老年代中。

 

4、动态年龄判断

动态对象年龄判定。当 Survivor 空间中相同年龄所有对象的大小总和大于 Survivor 空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,而不需要达到默认的分代年龄。

  • 9
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
Java垃圾回收机制中,堆内存被划分为不同的,其中年代(Old Generation)是其中的一部分。 年代主要用于存放生命周期较长的对象。这些对象通常是经过多次垃圾回收后仍然存活的对象。在新生代中经过一定次数的垃圾回收后,依然存活的对象会被晋升年代年代的垃圾回收主要采用标记-清除(Mark-Sweep)算法或标记-整理(Mark-Compact)算法。标记-清除算法首先标记所有存活对象,然后清除未标记的对象,释放空间。而标记-整理算法则会将存活对象向一端移动,然后清除其它端上的所有对象,使得内存空间连续。 年代的垃圾回收通常涉及到全局暂停(Stop-The-World)的情况。在垃圾回收期间,应用程序的执行会暂停,直到垃圾回收完成。这可能会对应用程序的性能和响应时间产生影响。为了减少全局暂停时间,Java虚拟机使用了一些优化技术,如并发标记、并发清除等,并发垃圾回收器(如CMS、G1)可以在一定程度上减少全局暂停的时间。 年代的大小通常比新生代大,并且在应用程序中往往存放着大量的对象。因此,合理配置年代的大小以及选择合适的垃圾回收器对于应用程序的性能和内存利用率至关重要。 总结来说,年代Java垃圾回收机制中用于存放生命周期较长对象的一部分堆内存。它采用标记-清除或标记-整理算法进行垃圾回收,通常涉及全局暂停,但可以通过并发垃圾回收器来减少暂停时间。合理配置年代的大小和选择合适的垃圾回收器对于应用程序的性能和内存管理至关重要。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java叶新东老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值