Java_Object_Model
2019-07-02 10:54:32 0 举报
AI智能生成
Java的对象模型
作者其他创作
大纲/内容
对象的创建过程
1:确定类元信息是否存在
当 JVM 接收到 NEW 指令时,首先在元空间内检查,需要创建的类元信息是否存在。
不存在:以 "ClassLoader + 包名 + 类名" 为 key ,查找对应的 .class 文件是否存在
不存在:抛出 ClassNotFoundException
存在:进行类加载,并生成对应的 Class 类对象
存在
2:为对象分配内存
计算对象占用空间大小,从堆中分配内存给新对象
注意:分配内存空间时,需要进行同步操作
比如采用 CAS 、区域加锁等方式,保证分配操作的原子性
3:设定默认值
成员变量设置默认值
4:设置对象头
5:执行 init 方法
对象的内存布局
对象头 (Header)
Markword:存储对象本身的运行时的数据
哈希码
GC 标记
GC 次数
监视器地址
线程栈锁记录地址
锁标志位
偏向锁标志位
线程 ID
......
类元信息
:在对象头中存储该对象的类元数据的指针
注意:并非在所有虚拟机实现中,都在对象头中保存了对象的类型指针
数组长度
如果是数组对象,对象头中必须有一块用来记录数组长度的数据
相关知识点
普通对象的对象头占用 2 个 words 内存空间
数组对象的对象头占用 3 个 words 内存空间
实例数据 (Instance Data)
实例数据的存储顺序,会受到虚拟机分配策略参数(FieldsAllocationStyle)和字段在源码中定义顺序的影响
Hotspot 默认分配策略为:longs/doubles、ints、shorts/chars、bytes/booleans、oops
相同宽度字段总是被分配都一起
满足该策略前提下,父类字段会出现在子类字段之前
JVM 的 CompactField 参数
如果为 true,则子类较窄变量,可能会出现在父类变量的空隙之中,以提高内存利用率
对齐填充 (Padding)
对象的存储空间分配单位为 8 个字节
相关知识点
查找对象的元信息,并不一定需要通过对象本身
对象的访问定位
句柄访问
:本地变量表中的 reference 变量存储句柄地址,句柄访问就是指通过句柄中存储的对象地址来访问对象
堆中会划分出一块内存做为 句柄池
句柄的存储结构
对象实例数据的地址信息
对象类型数据的地址信息
优势
由于 reference 中存储的是稳定的句柄地址,所以对象被移动时,只需改变句柄中的实例数据指针,reference 本身不需要修改
直接访问
:本地变量表中的 reference 变量直接存储对象的地址,直接访问就是指通过对象地址直接访问对象
优势
访问速度更快,节省了一次内存定位的开销
内存的分配方式
指针碰撞
(Bump The Pointer)
(Bump The Pointer)
假设堆中的内存是绝对规整的,所有用过的内存放一边,所有未用过的内存放另一边,中间放一个指针做为分界点的指示器,分配内存就是把那个指针,向空闲空间那边挪动一段与对象大小相等的距离
采用指针碰撞的垃圾回收器
Serial
ParNew
空闲列表
(Free List)
(Free List)
由虚拟机维护一个列表,记录哪些内存块是可用的,分配内存时寻找一块足够大的空间,划分给对象实例,并更新空闲列表的记录信息
采用空闲列表的了垃圾回收器
CMS
本地线程分配缓存(分而治之思想)
(Thread Local Allocation Buffer, TLAB)
(Thread Local Allocation Buffer, TLAB)
:将内存分配操作,按照线程划分在不同的空间中进行,即每个线程在堆中预先一小块内存,用作内存分配使用
内存分配流程
分配内存空间时,首先在 TLAB 中进行分配,如果 TLAB 不足,则尝试分配新的 TLAB 空间,在分配新空间时,才需要同步锁定进行
相关知识点
堆内存是否规整,由采用的垃圾回收器,是否带有压缩功能决定
重要知识点
为对象分配内存空间时,在并发情况下是线程不安全的,可能出现正在给对象 A 分配内存,指针还未修改,结果对象 B 又使用了原来的指针来分配内存
解决方案一:为对象分配内存空间时,进行同步处理
解决方案二:使用本地线程分配缓存(TLAB)的方式
0 条评论
下一页