中都

风习袅袅,盈水展千华,飞檐亭角清铃响。犹记当初,你回眸莞尔,一笑倾城百日香。

博客园 首页 新随笔 联系 订阅 管理

一、创建对象的过程

ⅰ 先加载类:

  1. 加载:将class文件加载进内存,在堆中生成对应的Class对象,作为访问方法区中类信息的入;
  2. 链接:(验证:class文件是否符合要求、准备:静态变量赋初值、解析:符号引用变为直接引用);
  3. 初始化:静态变量赋值;

ⅱ 分配对象空间:(类加载之后,对象的大小就完全确定了)

ⅲ 初始化实例变量为0值;

ⅳ 对象的初始设置(设置对象的对象头,这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息);

ⅴ init方法初始化,就是对象的实例属性的赋值;

 

二、对象的内存布局

对象在内存中存储的布局可以分为 3 块区域:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)。
 

对象头

HotSpot 虚拟机的对象头包含两部分信息。
  • 第一部分用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。
  • 对象的另一部分类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例(并不是所有的虚拟机实现都必须在对象数据上保留类型指针,也就是说,查找对象的元数据信息并不一定要经过对象本身)。
 
如果对象是一个 Java 数组,那在对象头中还必须有一块用于记录数组长度的数据。
 

实例数据

实例数据部分是对象真正存储的有效信息,也是在程序代码中定义的各种类型的字段内容,无论从父类继承下来的,还是在子类中定义的,都需要记录起来。这部分的存储顺序会受虚拟机默认的分配策略参数和字段在 Java 源码中定义的顺序影响(相同宽度的字段总是被分配到一起)。
规则:
  • 相同宽度的字段总是被分配在一起
  • 父类中定义的变量会出现在子类之前
  • 如果 CompactFields 参数为 true(默认true),子类的窄变量可能插入到父类变量的空隙
 

对齐填充

对齐填充部分并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。由于 HotSpot VM 的自动内存管理系统要求对象的起始地址必须是 8 字节的整数倍,也就是说,对象的大小必须是 8 字节的整数倍。而对象头部分正好是 8 字节的倍数(1倍或者2倍),因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。
 
我们通过一个简单的例子加深下理解:
 
public class PersonObject {
    public static void main(String[] args) {
        Person person = new Person();
    }
}
public class Person {
    int id = 1008;
    String name;
    Department department;
    {
        name = "匿名用户";   //name赋值为字符串常量
    }
}
public class Department {
    int id;
    String name;
}

posted on 2021-03-30 20:12  中都  阅读(19)  评论(0)    收藏  举报
Live2D