jvm之对象的创建与内存模型解析

本文详细介绍了Java对象的创建过程,包括类加载检查、内存分配(指针碰撞法和空闲列表法)、初始化、设置对象头以及并发分配问题的解决方案。接着,讨论了JVM内存模型,包括堆内存、方法区、栈内存、本地方法栈和程序计数器。最后,讲解了对象内存分配,特别是逃逸分析和标量替换的概念,以及它们如何影响GC行为。通过对JVM参数的调整,可以优化内存使用和GC效率。
摘要由CSDN通过智能技术生成

一、对象的创建

之前一篇详细分析过类的加载,本篇主要记录分析对象的创建步骤以及jvm内存的分配。

直接上图

显而易见,对象的创建大致经过7个步骤:

1.类是否加载判断,如果想要创建一个类的实例对象,首先这个类是要被加载完成之后才可以,所以第一步就要判断类是否被加载过,若未被加载,则先加载类。

2.内存分配,创建对象之前首先需要在堆中分配一块足够大的内存空间,具体多大,这个在对应的类加载完成之后,jvm就已经可以确定这类的对象需要占用多大的内存了,所以只要在堆内存中划分一块确定的内存空间即可。内存分配的方式有两种:

  • 指针碰撞法:堆内存中的空间比较规整,所有已经使用的内存空间规整的排列在一起,然后使用一个指针把已使用的内存空间和未使用的内存空间分隔开来,当一个对象需要分配内存时,只需要把指针向后移动对象需要的大小即可,jvm默认使用这种方法。
  • 空闲列表法:对象在堆内存中的分配比较随意凌乱,所以jvm在内部维护了一个可用内存列表,当一个对象需要分配内存时,在空闲列表找出一块足够大的内存给新生对象,然后这块内存从空闲列表中移除。

内存分配的并发问题:

不管使用哪种分配方式都有并发问题,例如:使用指针碰撞法分配内存空间,A对象和B对象同时获取到指针,给A分配内存后,B又使用老的指针进行分配。

解决方案:

  • 使用CAS+重试的方式分配内存,在内存分配时,使用CAS原子操作进行内存的分配,如果CAS操作失败的就进行重试  一直到成功为止,这种方式性能较低。
  • 本地线程缓冲(Thread Local Allocation Buffer,TLAB),这堆中种方式就是预先在给线程分配一块空间,之后每个线程需要创建对象,就在属于自己的堆内存空间中分配,这样就避免了并发分配问题,这种是JVM默认的解决并发分配的方式,可以使用配置参数:-XX:+/-UseTLAB配置是否开启此方法(默认开启),-XX:TLABSize配置TLAB的大小。

3.初始化

在堆中给新生对象分配好内存空间之后,虚拟机把分配到的这块内存空间都初始化为零(不包括对象头),如果使用了TLAB,这一过程也可以提前至TLAB分配时进行,这样可以保证对象的实例在java代码中不赋初始值就可以使用,程序可以访问到这些字段的零值。

4.设置对象头

java对象包括三个部分,对象头,实例数据区,对齐填充位,其中对象头中保存了对象的hashCode,分代年龄,锁的标志位信息,这一块被称为mark word,除此之外还有类元信息指针,针对数组对象还记录了数组长度等信息,所以一个对象被创建成功前是需要设置对象头的信息的,换句话说,就是把对象的hashCode、分代年龄,类元信息指针都赋好值。

针对对象头这一块做一个特别说明:

对象头也有三块组成:

  • mark word:在32位操作系统中,占4个字节 ,在64位操作系统下占8个字节,如下

    锁状态

    25bit

    4bit

    1bit

    2bit

    23bit

    2bit

    是否偏向锁

    锁标志位

    无锁

    对象的HashCode

    分代年龄

    0

    01

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值