对象的创建

虚拟机遇到一个new指令的时候,根据new指令的参数是否能在常量池中定位到一个类的符号引用,并检查符号引用代表的类是否已经加载、解析、初始化。如果没有,必须先执行类加载。类加载通过之后,虚拟机为新生的对象分配内存。
根据内存是否规整,分配内存有两种方式:空闲列表、指针碰撞
如果java堆中内存绝对规整,使用指针碰撞:在可用内存和已经使用的内存之间有一个指针,给对象分配内存的时候,指针向可用空间的那一侧移动和对象大小相等的距离。
如果java堆中的内存不是规整的,使用空闲列表:虚拟机维护了一个列表,列表中记录着哪些内存块时可用的,分配的时候根据这个表找到一块足够大内存划分给对象,并且更新这个列表。
使用指针碰撞分配内存的时候需要考虑并发的情况,因为创建对象在虚拟机中是一个很频繁的行为,如果一个对象正在分配内存,还没有来得及修改指针,此时又有一个对象使用原来的指针分配内存,这样就会产生冲突。
解决这个问题有两种方案:1:对分配内存空间的动作进行同步的处理(实际上使用的是CAS配上失败重试的方式保证更新操作的原子性)。2:把内存分配的动作按照线程划分在不同的空间进行。即:每个线程在java堆中预先分配一小块内存,称为本地线程分配缓冲(TLAB),哪个线程要分配空间,就在哪个线程的TLAB上分配,只有TLAB用完并分配新的TLAB的时候才需要同步锁定。
内存分配完成后,需要将分配到的内存空间初始化为零值(不包括对象头),这一步保证对象的实例字段即使在java中没有赋初值就可以使用。
虚拟机对对象进行必要的设置,例如对象是哪个类的实例、如何才能找到类的元数据、对象的哈希码、对象的GC分代年龄等,这些信息存放在对象头中。
此时从虚拟机的角度来看,新的对象已经产生,但是从java的角度来看,对象创建才刚刚开始,因为<init>还没有执行,所有的字段为零。一般来说,执行new指令之后接着会执行<init>方法(执行不执行还得看是否有invokespecial指令)。这样,一个对象就创建了
对象由三个部分组成:对象头、实例数据、对齐填充
对象头包括:存储对象自身的运行时数据、类型指针、数组长度(如果是数组对象的话)
运行时数据:对象的哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等
类型指针:对象指向类元数据的指针,虚拟机通过该指针确定是这个对象是哪个类的实例
通过栈上的reference数据来操作堆上的具体对象:
句柄访问:
堆:句柄池、实例池;
句柄池:到对象实例数据的指针、到对象类型数据的指针;
栈(本地变量表):reference数据;
方法区:对象类型数据
直接指针:
堆:对象实例数据;
栈(本地变量表):reference数据;
对象实例数据:实例数据、到对象类型数据的指针
方法区:对象类型指针

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值