对象实例化
创建对象的方式
- new对象和调用静态方法
- Class的newInstance() 反射方式,只能调用空参构造器,权限public
- Constructor的newInstance(xxx) : 反射方式,可以空参,有参构造器,无权限要求
- 使用clone() : 不调用任何构造器,需实现CLoneable接口的clone()方法
- 使用反序列化 : 从文件中等获取一个对象的二进制流
- 第三方库Objenesis
创建对象的步骤
- 判断对象对应的类是否加载,链接,初始化
- 为对象分配内存
- 如果内存规整–指针碰撞
- 如果内存不规整: 维护一个列表,空闲列表分配
- 处理并发安全问题
- 采用CAS配上失败重试保证更新的原子性
- 每个线程预先分配一块TLAB
- 初始化分配到的空间 – 所有属性设置默认值,保证对象实例字段在不赋值时可以直接使用
- 设置对象的对象头
- 执行init方法初始化
对象内存布局
对象头
- 运行时元数据
- 哈希值
- GC分代年龄
- 锁状态标志
- 线程持有的锁等
- 类型指针: 指向类元数据的InstanceKlass,确定该对象所属类型
- 说明: 如果是数组,还需记录数组的长度
实例数据
是对象真正存储的有效信息,包括程序代码中定义的各种类型的字段(包括父类继承和本身的字段)规则
- 宣布该提报过挤压不低于的字段总是被分配在一起
- 父类中定义的变量会出现在子类之前
- 如果CompactFields 参数为true()默认), 子类的窄变量可能插入到父类变量的空隙
对齐填充
非必须,无特别含义,起占位符作用
对象访问定位
通过栈上栈帧(reference)访问定位
对象访问主要两种方式
句柄访问
直接指针(HotSpot)
直接内存
- 非虚拟机运行时数据区的一部分,也不是<Java虚拟机规范>中定义的内存区域
- 直接内存时堆外的,直接向系统申请的内存
- 访问直接内存的速度会优于java堆,读写性能高
- 也可能导致OOM异常
- 优于直接内存在Java堆外,因此他的大小不会直接受限于 -Xmx 指定的最大堆大小,但系统内存有限,Java堆和直接内存的总和任然受限于操作系统给出的最大内存
- 缺点
- 分配回收成本较高
- 不受JVM内存回收管理
- 直接内存大小可以通过MaxDirectMemorySize设置
- 默认与堆的最大值 -Xmx值一致
java process memory = java heap + native memory