JVM-JVM中对象的生命周期

这篇具有很好参考价值的文章主要介绍了JVM-JVM中对象的生命周期。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

申明:文章内容是本人学习极客时间课程所写,文字和图片基本来源于课程资料,在某些地方会插入一点自己的理解,未用于商业用途,侵删。
原资料地址:课程资料

对象的创建

JVM-JVM中对象的生命周期,JVM虚拟机,jvm,年轻代,老年代,内存分配,内存担保

常量池检查:检查new指令是否能在常量池中定位到这个类的符号引用,检查类之前是否被加载过。如果已经加载则直接使用,否则需要进行加载。
分配内存空间
有两种方式:

  • 指针碰撞 由Serial 和 ParNew去回收
  • 空闲列表 有CMS和Mark-Sweep回收
    必要信息的设置:对象的元数据,对象哈希码,GC分代年龄 -> 对象头
    JVM-JVM中对象的生命周期,JVM虚拟机,jvm,年轻代,老年代,内存分配,内存担保
    指针碰撞往往是一片连续的区域,空闲列表是非连续的。
    JVM-JVM中对象的生命周期,JVM虚拟机,jvm,年轻代,老年代,内存分配,内存担保
    内存分配存在的问题
    1 线程安全问题,因为堆是共享的,如果多个线程同时执行可能存在线程安全问题。
    解决方案:
    1) 通过CAS乐观锁:IVM虚拟机采用CAS失败重试的方式保证更新操作的原子性
    2)TLAB (Thread LocalAllocation Buffer) 本地线程分配缓存,预分配(也就是先给这个线程分配一个私有的内存,这样就不会有并发问题)
    分配主流程:首先从TLAB里面分配,如果分配不到,再使用CAS从堆里面划分

分配内存分配是是老年代还是年轻代
内存的分配大多数new出来的对象都是新生代,但是也有部分会去到老年代(比如大对象,在新生代无法放下)。
必要信息设置
对象类的元数据,对象哈希码,GC分带年龄(存储在对象头中)

对象进入老年代

JVM-JVM中对象的生命周期,JVM虚拟机,jvm,年轻代,老年代,内存分配,内存担保
进入老年代的条件
1 存活年龄太大,默认超过15次【-XX:MaxTenuringThreshold】(GC过程中会讲)
JVM-JVM中对象的生命周期,JVM虚拟机,jvm,年轻代,老年代,内存分配,内存担保
1 在MinorGC的时候存活的对象会被复制到幸存区域年龄 + 1 2 下一次GC的时候幸存取的对象和Eden的对象存活的对象会被复制到第二块幸存区域 年龄 + 1 3 这样来回复制如果对象的年龄大于15就会放入老年代,可以修改这个值
2 动态年龄判断:MinorGC之后,发现Survivor区中的一批对象的总大小大于了这块Survivor区的50%,那么就会将此时大于等于这批对象年龄最大值的所有对象,直接进入老年代。
-XX:TargetSurvivorRatio可以指定
举个栗子:Survivor区中有一批对象,年龄分别为年龄1+年龄2+年龄n的多个对象,对象总和大小超过了Survivor区域的50%,此时就会把年龄n及以上的对象都放入老年代。
为什么会这样?
希望那些可能是长期存活的对象,尽早进入老年代。

3 大对象直接进入老年代:前提是Serial和ParNew收集器
大对象可以通过这个参数去配置: -XX:PretenureSizeThreshold 一般设置为1M
举个栗子:字符串或数组
为什么会这样?为了避免大对象分配内存时的复制操作降低效率。避免了Eden和Survivor区的复制

空间担保机制:当新生代无法分配内存的时候,我们想把新生代的老对象转移到老年代,然后把新对象放入腾空的新生代。此种机制我们称之为内存担保。
4 MinorGC后,存活对象太多无法放入Survivor

  • MinorGC前,判断老年代可用内存是否小于新时代对象全部对象大小,如果小于则继续判断老年代可用内存大小是否小于之前每次MinorGC后进入老年代的对象平均大小
    如果是,则会进行一次FullGC,判断是否放得下,放不下OOM
    如果否(代表老年代能放下),则会进行MinorGC:
    MinorGC后,剩余存活对象小于Survivor区大小,直接进入Survivor区
    MinorGC后,剩余存活对象大于Survivor区大小,但是小于老年代可用内存,直接进入老年代
    MinorGC后,剩余存活对象大于Survivor区大小,也大于老年代可用内存,进行FullGC
    FullGC之后,任然没有足够内存存放MinorGC的剩余对象,就会OOM
    JVM-JVM中对象的生命周期,JVM虚拟机,jvm,年轻代,老年代,内存分配,内存担保

案例1,大对象直接进入老年区:

// -Xmx60m -Xms60m -XX:NewRatio=2 -XX:SurvivorRatio=8 -XX:+PrintGCDetails
// Xmx 程序运行时最大内存大小
// Xms 程序启动时最大内存大小
// NewRatio 年轻代和老年代的比例为1:2
// SurvivorRatio survivor区域和eden 区域的内存比例 1 : 8
// PrintGCDetails 打印详细日志
public static void main(String[] args) {
       byte[] buffer = new byte[1024*1024*20];
 }

JVM-JVM中对象的生命周期,JVM虚拟机,jvm,年轻代,老年代,内存分配,内存担保
JVM-JVM中对象的生命周期,JVM虚拟机,jvm,年轻代,老年代,内存分配,内存担保
由这个例子我们可以得出结论因为年轻代的内存总共也就18M左右导致年轻代无法存放我们创建的20M大小的数组,所以直接放入到了老年代。
案例2:

// -Xmx600m -Xms600m -XX:+PrintGCDetails
public class HeapInstance {
    public static void main(String[] args) {
        List<Picture> list = new ArrayList<>();
        while (true) {
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            list.add(new Picture(new Random().nextInt(1024 * 1024)));
        }
    }
}

public class Picture {
    private byte[] pixels;
    public Picture(int length){
        this.pixels = new byte[length];
    }
}

与前面的描述呼应,进行三次FG后任然无法分配内存,则OOM。整个过程大致是这样,我们不断地创建对象,然后Eden区逐渐被占满,从而一部分对象复制到幸存区,然后幸存区(这个过程中会有动态年龄的判断来回复制)放不下了进入老年区,直到老年区也无法放下就内存溢出。
JVM-JVM中对象的生命周期,JVM虚拟机,jvm,年轻代,老年代,内存分配,内存担保

案例3,动态内存担保机制的演示:
空间担保机制:当新生代无法分配内存的时候,我们想把新生代的老对象转移到老年代,然后把新对象放入腾空的新生代。此种机制我们称之为内存担保。

// -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseSerialGC
// 初始内存  最大内存  年轻第空间  
public class Demo {
    private static final int _1MB = 1024 * 1024;
    public static void main(String[] args) {
        memoryAllocation();
    }
    public static void memoryAllocation() {
        byte[] allocation1, allocation2, allocation3, allocation4;
        allocation1 = new byte[1 * _1MB];//1M
        allocation2 = new byte[1 * _1MB];//1M
        allocation3 = new byte[1 * _1MB];//1M
        allocation4 = new byte[5 * _1MB];//5M
        System.out.println("完毕");
    }
}

JVM参数
JVM-JVM中对象的生命周期,JVM虚拟机,jvm,年轻代,老年代,内存分配,内存担保
可以看到老年代存了一个大约3M的对象,年轻代存大约6M的一个对象。
那么它执行的流程是这样的,前面3M的对象在eden区域分配后,后面来了一个5M的对象,发现内存不足,于是将之前3M 的数据移入了老年代,之后将5M的数据放入新生代,这就是内存担保机制。文章来源地址https://www.toymoban.com/news/detail-829945.html

到了这里,关于JVM-JVM中对象的生命周期的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java虚拟机(JVM)垃圾收集器、新生代、老年代、永久代以及内存分配策略

    在 Java 中,堆被划分成两个不同的区域:新生代 ( Young )、老年代 ( Old )。而新生代 ( Young ) 又被划分为三个区域:Eden、From Survivor、To Survivor。这样划分的目的是为了使 JVM 能够更好的管理堆内存中的对象,包括内存的分配以及回收。 新生代中一般保存新出现的对象,所以每次

    2024年02月04日
    浏览(84)
  • JVM工作原理与实战(六):类的生命周期-连接阶段

    JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、类的生命周期 1.加载(Loading) 2.连接(Linking) 3.初始化(Initialization) 4.使用(Using) 5.卸载(Unloading) 二、连接阶段 1.验证 2.准备 3.解析 总结 JVM作为Java程序的运行环境,其负责解释和执行字

    2024年02月02日
    浏览(39)
  • JVM-JVM调优基础(理论)

    申明:文章内容是本人学习极客时间课程所写,作为笔记进行记录,文字和图片基本来源于课程资料,在某些地方会插入一点自己的理解,未用于商业用途,侵删。 原资料地址:课程资料 JVM参数 标准参数 定义:稳定的参数不会随着Java版本的变化而变化。通常以 短横线开头

    2024年02月19日
    浏览(37)
  • JVM——类的生命周期(加载阶段,连接阶段,初始化阶段)

    类的生命周期 ⚫ 1、加载(Loading)阶段第一步是类加载器根据类的全限定名通过不同的渠道以二进制流的方式获取字节码信息。 程序员可以使用Java代码拓展的不同的渠道。 ⚫ 2、类加载器在加载完类之后,Java虚拟机会将字节码中的信息保存到方法区中。 ⚫ 3、类加载器在加载

    2024年02月05日
    浏览(50)
  • JVM包含哪几部分?JVM内存模型?线程的生命周期? 对Spring AOP的理解?布隆过滤器

    JVM由三部分组成:类加载子系统、执行引擎、运行时数据区。 类加载子系统:可以根据指定的全限定名来载入类或接口。 执行引擎:负责执行那些包含在被载入类的方法中的指令。 运行时数据区:当程序运行时,JVM需要内存来存储许多内容,例如:字节码、对象、参数、返

    2024年02月16日
    浏览(47)
  • JVM基础(10)——老年代调优

    作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 学习必须往深处挖,挖的越深,基础越扎实! 阶段1、深入多线程 阶段2、深入多线程设计模式 阶段3、深入juc源码解析

    2024年01月20日
    浏览(40)
  • JVM虚拟机:定位对象的两种方式

    1、句柄池 2、直接指针 ‘句柄池  直接指针   在Java中,可以使用两种方式来定位对象:句柄池和直接指针。 1. 句柄池:在Java的句柄池模型中,Java虚拟机(JVM)会为每个对象创建一个句柄,句柄包含了对象的实例变量和一个指向对象实例数据的指针。当我们需要访问对象时

    2024年02月11日
    浏览(40)
  • JVM内存02-新生代和老年代介绍:

    JVM 中新生代和老年代的比例大小是可以通过参数进行调整的。 默认情况下,新生代和老年代的比例是 1:2, 也就是新生代占整个堆空间的 1/3,老年代占整个堆空间的 2/3。 可以使用 JVM 参数 -XX:NewRatio=n 来调整新生代和老年代的比例。 其中,n 表示老年代和新生代的比例, 比

    2024年02月16日
    浏览(38)
  • 深入理解Java虚拟机jvm-对象的内存布局

    在HotSpot虚拟机里,对象在堆内存中的存储布局可以划分为三个部分:对象头(Header)、实例 数据(Instance Data)和对齐填充(Padding)。 HotSpot虚拟机对象的对象头部分包括两类信息。第一类是用于存储对象自身的运行时数据,如哈 希码(HashCode)、GC分代年龄、锁状态标志、

    2024年02月09日
    浏览(55)
  • JVM类的声明周期

    本博客的内容基于我个人学习黑马程序员课程的学习笔记整理而成。我特此声明,所有版权属于黑马程序员或相关权利人所有。本博客的目的仅为个人学习和交流之用,并非商业用途。 我在整理学习笔记的过程中尽力确保准确性,但无法保证内容的完整性和时效性。本博客的

    2024年02月05日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包