对象的实例化;对象的创建方式 创建对象的步骤
创建对象的六个步骤:
- 判断对象对应的类是否加载、链接、初始化
- 为对象分配内存:
如果内存规整->指针碰撞:
如果内存不规整->虚拟机需要维护一个列表,进行空闲列表分配
具体选择哪种分配方式由java堆是否规整,而java堆是否规整又由所采取的垃圾收集器是否带有压缩整理功能决定。
- 处理并发安全问题
采用CAS失败重试,区域加锁保证更新的原子性
每个线程预先分配一个TLAB,通过-XX:+/-UseTLAB参数来设定
- 初始化分配到的空间:对对象的属性默认初始化(赋默认初始化值)
- 设置对象的对象头
- 执行init方法进行初始化(显示初始化、代码块初始化、构造器中初始化)
对象的内存布局:对象头、实例数据、对齐填充
- 对象头:主要包含两部分,运行时元数据和类型指针
运行时元数据:
- 哈希值
- GC分代年龄
- 锁状态标志
- 线程持有的锁
- 偏向线程ID
- 偏向时间戳
类型指针:指向类元数据InstanceKlass,确定该对象所属的类型
注:如果创建的是数组,还需要记录数组的长度
- 实例数据:它是对象真正存储的有效信息,包括程序代码中定义的各种类型的字段(包括从父类继承下来的和本身拥有的字段)
规则:相同宽度的字段总是被分配在一起
父类中定义的变量会出现在子类之前
如果CompactFields参数为true(默认为true),子类的窄变量可能插入到父类变量的空隙
- 对齐填充:不是必须的,也没什么特殊含义,仅仅起到占位符的作用
举例:Customer cust=new Customer();内存布局图:
对象的访问定位:JVM是如何通过栈帧中的对象引用访问到其内部的对象实例的?
图示:
- 访问对象的方式:句柄访问、直接指针
句柄访问:
直接指针:
句柄访问、直接指针访问优缺点:
句柄访问需要单独开辟句柄池,浪费空间,且访问时需要经过句柄池访问类元信息和对象实例数据,访问效率较慢。
句柄访问的优点:在栈中维护的reference地址比较稳定,
本文含有隐藏内容,请 开通VIP 后查看