JVM学习之对象的实例化

283 阅读3分钟

一、对象的实例化

1、对象的创建方式

  • new:通过new关键字去创建对象
  • Class的newInstance():通过反射的方式,只能调用无参的构造方法,权限必须是public
  • Constructor的newInstance():通过反射的方式,可以调用无参、有参的构造方法,权限没有限制
  • 使用clone():类必须实现cloneable接口,实现clone()方法,属于浅拷贝
  • 通过反序列化的方式创建对象

2、对象创建的步骤

  • 判断对象的对应的类是否加载、链接、初始化。
    • jvm遇到一个new指令,首先去检查这个指令的参数能否在常量池中定位一个类的符号引用,并且检查这个符号引用代表的类是否被加载、解析和初始化。如果没有,那么在双亲委派模式下,使用当前的类加载器以及全限定名的方式去查找class文件,没有找到就报classnotfoundexception异常;如果找到,则进行类的加载,并产生class类对象
  • 为对象分配内存。
    • 首先需要计算对象 占用的内存空间的大小,除了double和long类型占用8字节,其余占用4字节。
    • 如果内存是规整的,可以采用指针碰撞发为对象分配内存空间:意识是所有用过的内存在一边,空闲的内存在另外一边,中间放着一个指针作为分界点的指示器,分配内存就仅仅是把指针为空闲那边挪动一段与对象大小相等的举例罢了。
    • 如果内存不是规整的,jvm将采用的是空闲列表法为对象分配内存。意思是虚拟机维护一个列表,记录上哪些内存块是可用的,再分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的内容。
  • 处理并发问题
    • 采用cas失败重试,区域加载保证更新的原子性
    • 为每个线程分配tlab
  • 初始化分配到的空间
    • 为对象进行默认初始化,保证对象在没有赋值时,就可以直接使用。
  • 设置对象头
    • 将对象的所属类、对象的hashcode和对象的gc信息、锁信息等数据信息存储在对象头中
  • 执行init方法进行显示初始化
    • 执行类的构造器

二、对象的内存布局

对象在堆中的内存布局一个有3部分:
(1)对象头
(2)实例数据
(3)对齐填充
  • 对象头:包含2部分内容:(1)运行时元数据(2)类型指针
    • 运行时元数据:哈希值、GC分配年龄、锁状态标志、线程持有的锁
    • 类型指针:指向类元数据,确定对象所属的类型
  • 实例数据:存放父类、子类的字段值
  • 对齐填充:没啥含义

三、对象的访问定位

如果通过栈帧中的引用访问堆中的对象?
  • 句柄访问:堆中维护一个列表,列表中记录指针地址和堆中对象实际地址。
  • 直接指针:通过直接指针找到堆中的对象地址。