文章目录

  • 1 对象实例化
  • 1.1 创建对象的方式
  • 1.2 字节码角度查看创建对象
  • 1.3 对象创建的步骤
  • 1.3.1 判断对象对应的类是否加载,链接,初始化
  • 1.3.2 为对象分配内存
  • 1.3.3 处理并发安全问题
  • 1.3.4 初始化分配到的空间
  • 1.3.5 设置对象的对象头
  • 1.3.6 执行init方法进行初始化
  • 2 对象的内存布局
  • 2.1 对象头
  • 2.2 实例数据
  • 2.3 对齐填充
  • 3 对象访问定位
  • 3.1 句柄访问
  • 3.2 直接指针(hotspot采用)


1 对象实例化

1.1 创建对象的方式

  • new

变形1:XXX的静态方法
变形2:XXBuilder/xxFactory的静态方法

  • Class的newInstance()

反射的方式,只能调用空参的构造器,权限必须是public

  • Construtor的newInstance(xxx)

反射的方式,可以调用空参,带参的构造器,权限没有要求

  • 使用clone()

不使用任何构造器,当前类需要实现cloneable接口,实现clone()

  • 使用反序列化

从文件中,从网络中获取一个对象的二进制字节流。

1.2 字节码角度查看创建对象

代码

/**
 * @program: jvmDemo
 * @description:
 * @author: wfg
 * @create: 2021-06-18 12:10
 */
public class Test12 {
    public static void main(String[] args) {
        Object obj = new Object();
    }
}

Java 在对象中 获取对象地址 jvm获取对象信息_jvm

本人菜鸡,感兴趣的可以查看底层汇编


1.3 对象创建的步骤

  1. 加载类元信息
  2. 为对象分配内存
  3. 处理并发问题
  4. 属性的默认初始化
  5. 设置对象头信息
  6. 属性的显示初始化,代码块中初始化,构造器初始化

1.3.1 判断对象对应的类是否加载,链接,初始化

虚拟机遇到一条new指令,首先检查这个指令的参数能否在Metaspace的常量池中定位到一个类的符号引用,并且检查这个符号引用的类已经被加载,解析和初始化(判断类元信息是否存在),如果没有则在双亲委派模式下,使用当前类加载器进行查找对应的.class文件。没有找到就抛出ClassNotFoundException 异常,找到则进行类加载并生成Class类对象

1.3.2 为对象分配内存

首先计算对象占用空间大小,接着在堆中划分一块内存给新对象。如果实例成员变量是引用变量,仅分配引用变量空间即可,4个字节大小。

内存分配

  • 内存规整

jvm 采用的是指针碰撞,用过的内存在一边,空闲的内存在另外一边,中间放一个指针作为分界点的指示器,分配内存就是把指针向空闲那边移动一段与对象大小相等的距离。

  • 内存不规整

首先jvm需要维护一个列表,记录那些内存块时可用的,在分配的时候从列表中找到一块足够空间分给对象实例,并更新列表上的内容。

  • 说明

选择哪种分配方式是由java堆是否规整决定的,而java堆是否规整是由所采用的垃圾收集器是否带有压缩整理功能决定的

1.3.3 处理并发安全问题
  • 采用cas失败重试,区域加锁保证更新的原子性。
  • 每个线程预先分配一块tlab
1.3.4 初始化分配到的空间

所有属性设置默认值,保证对象实例字段在不赋值时可以直接使用

1.3.5 设置对象的对象头

将对象的所属类(元数据信息),对象的hashcode 和对象的gc信息,锁信息数据存储在对象的对象头

1.3.6 执行init方法进行初始化

在java程序的视角,初始化才刚开始。初始化成员变量,执行实例化代码块,调用类的构造方法,并把对内对象的首地址赋值给引用变量。

2 对象的内存布局

2.1 对象头

主要包含两部分: 运行时元数据和类型指针,数组的话还记录了数组的长度

运行时元数据

  • 哈希值(hashcode)
  • gc分代年龄
  • 锁状态标志
  • 线程持有的锁
  • 偏向线程id
  • 偏向时间戳

类型指针

指向元数据instanceKlass,确定对象所属的类型(元空间内的类元数据,主要用于判断是属于哪个类的实例)

2.2 实例数据

它是对象真正存储的有效信息,包括程序代码中定义的各种类型的字段

2.3 对齐填充

不是必须的,仅起到占位符的作用


代码

/**
 * @program: jvmDemo
 * @description:
 * @author: wfg
 * @create: 2021-06-18 15:50
 */
public class Customer {
   int id =100;
   String name;
   Account account;

    {
        name="匿名客户";
    }

}
class Account{

}

使用

/**
 * @program: jvmDemo
 * @description:
 * @author: wfg
 * @create: 2021-06-18 15:55
 */
public class Test13 {
    public static void main(String[] args) {
        Customer cust = new Customer();
    }
}

流程图

Java 在对象中 获取对象地址 jvm获取对象信息_java_02

3 对象访问定位

主要有两种 句柄访问与直接指针

3.1 句柄访问

Java 在对象中 获取对象地址 jvm获取对象信息_jvm_03

3.2 直接指针(hotspot采用)

Java 在对象中 获取对象地址 jvm获取对象信息_初始化_04