对象的创建和访问
1 对象的创建过程
当java虚拟机遇到一条字节码new指令时
(1)检查这个指令的参数能否在常量池定位到一个符号引用
(2)检查该引用是否加载,解析,初始化过,如果没有,先加载类
(3)虚拟机为新生代分配内存
(4) 对对象进行必要的设置
将对象的元信息,对象的哈希值,GC分代年龄等信息存放在对象头
从虚拟机视角看,一个对象已经产生
但是从java程序的视角,对象的创建才刚开始
1.1对象的分配方式
对象的分配方式有两种:
(1)指针碰撞:
就只是将指针向空闲的一边挪动一段与对象大小相等的距离
如果已经使用的内存和空闲的内存交错在一起,就没有办法使用指针碰撞
(2)压缩指针:
虚拟机需要维护一个列表,记录哪些内存时可用的
分配的时候找到一块足够大的空间划分给对象实例
跟新列表上的记录
1.2 创建对象的线程安全问题
创建对象时非常频繁的行为,可能出现正在给A分配内存,指针还未来得及修改,B又使用了原来的指针
解决这个问题有两个方案:
(1) 对分配的内存的动作进行同步处理
实际上虚拟机时采用CAS+失败重试的方式保证更新操作的原子性
(2)将内存分配的动作按照线程划分在不同的空间内进行
每个线程在java堆中预先分配一小块内存(本地线程分配缓冲区 TLAB)
那个线程要分配内存,就在那个线程的本地缓冲区分配
只有本地线程分配完了,分配新内存时才需要同步
TLAB 通过 -XX:+/-UseTLAB 设置
2 对象的访问方式
主流的访问方式有句柄访问和直接访问:
(1)句柄访问:
从java堆中划分出一块内存作为句柄池
reference(引用类型)存储的就是对象的句柄地址
句柄中包含了对象实例数据和类型数据各自的指针
当对象被移动时(垃圾回收对象移动是很普遍的行为)只需改变句柄中的指针就好
无需改变reference
(2)直接指针:
reference 存储的就是对象的地址
如果只是访问对象本身,就无需多一次开销,速度更快
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200724211921260.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2t6bnNicw==,size_16,color_FFFFFF,t_70)