JVM篇:对象的深度剖析

对象的创建过程

image.png

  • 1.检查类是否被加载: 当jvm遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程。
  • 2.分配内存: 给这个对象划分一块空间,这个空间的大小是通过常量池里的类元信息来确定的。
  • 3.初始化: 给对象的成员变量赋默认值,int = 0,boolean = false等,保证了对象的实例字段在Java代码中可以不赋初始值就直接使用。
  • 4.设置对象头: 将KlassPointer、MarkWord、数组长度(只有数组对象有)等信息封装到对象头里面。
  • 5.执行init方法: 这个init方法是C++里面对应的那个用来创建java对象的struct对象的方法,这个方法会给对象的属性赋值,调用java对象的构造器。

内存的分配方式

内存划分

针对堆内存现有的规整情况不同,给对象分配内存的方式也不同,这和具体的垃圾回收器有关系。默认情况下第一次分配内存或者内存结构很规整的情况下使用指针碰撞,如果内存不规整的话使用空闲列表

  • 指针碰撞: 将已使用过的内存和未使用过的内存各放一边,使用一个已使用的内存的偏移量的指针来指向最近分配过的内存的地址,如果有新的对象需要分配内存则指针会向后移动对象大小的空间。
  • 空闲列表: 在虚拟机内部维护了一个列表,记录着哪些内存是可用的,在分配内存的时候从列表中找到一块对象大小的空间划分给对象,并更新列表上的记录。

并发处理

两种分配内存的方式都会遇到并发分配内存的线程安全问题,针对这种问题也有2种解决办法,循环CAS本地线程分配缓冲(TLAB)

  • 循环CAS: 使用过多线程的同学都知道这种方式,就是把内存中的预期值拿出来进行更新,在更新之前再判断一下当内存中现有的值和预期值是否一致,不一致则重新获取预期值,一致的话直接进行更新。但是这种方式会出现因自旋太久带来的cpu开销问题,所以默认使用的是TLAB方式解决。
  • 本地线程分配缓冲(Thread Local Allocation Buffer): 为每个线程都预先分配一块空间去划分内存,每个线程来了都从自己的空间里去分配内存。如果预留的内存不够划分则会回退到CAS的方式;可以通过-XX:TLABSize=xx来设置预留的大小,避免回退到CAS。

补充:这里我们要注意一个细节:对象的半初始化问题。

对象的组成结构

我们java的对象不仅仅只有成员变量,这个层面的理解太浅了,实际上java的对象包含了3个部分:对象头实例数据对齐填充

image.png

  • 对象头:对象头是Java对象中非常重要的一部分,他存储了对象的各种底层信息:比如MarkWord、KlassPointer、数组长度
  • 实例数据:实例数据就是我们对象拥有的属性。
  • 对其填充:因为是64bit操作系统,内存的宽度是64bit也就是8字节,8的整数倍寻址会更高效,对对象大小进行补位的,有中间对齐和尾部对齐。

对象头

下面我们深入对象头看看,到hotspot源码中找到markOop.hpp文件,看下注释怎么描述对象头的:

// Bit-format of an object header (most significant first, big endian layout below):
//
//  32 bits:
//  --------
//             hash:25 ------------>| age:4    biased_lock:1 lock:2 (normal object)
//             JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)
//             size:32 ------------------------------------------>| (CMS free block)
//             PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
//
//  64 bits:
//  --------
//  unused:25 hash:31 -->| unused:1   age:4    biased_lock:1 lock:2 (normal object)
//  JavaThread*:54 epoch:2 unused:1   age:4    biased_lock:1 lock:2 (biased object)
//  PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
//  size:64 ----------------------------------------------------->| (CMS free block)
//
//  unused:25 hash:31 -->| cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && normal object)
//  JavaThread*:54 epoch:2 cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && biased object)
//  narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
//  unused:21 size:35 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值