深入理解Java虚拟机之对象的创建-内存布局-访问定位
JSON Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
创建Java对象
从虚拟机角度来讲,创建一个对象有一下几步骤 1、分配空间 一般有两种办法 a、如果在堆内存中是规整的即使用过的内存和未使用的内存是分开的存放的,一边是使用过的一边是没有使用的 中间通过一个指针分割(bump the pointer 指针碰撞) b、维护一个列表其中保存着哪些地址被使用哪些空闲(Free List 空闲列表) 2、同步创建对象 a、虚拟机使用CAS+失败重试 保证对象同步创建 b、每个线程分配一块内存,线程在各自分配的内存中创建对象,只有在分配的内存不够时才需要加锁同步分配内存 3、初始化对象 此时,对象已经创建但是其中的字段还是默认值,按照穿入的参数初始化每一个字段 Java对象在内存中分3部分(内存布局) java头 >>Java对象的运行时数据,hash码,GC分代年龄等信息 >>指向Java对象元数据的引用(并不是所有的虚拟机都需要在对象头中保存次指针) Java体(实例数据) >>存储java对象真正的数据(字段的值等信息无论是自己的还是从父类继承下来的都要保存) 对齐填充 >>并非一定要存在,仅仅起到占位符的作用 |
JSON Code
1
2 3 4 5 6 7 |
Java对象的定位 我们操作对象都是通过虚拟机栈中的引用去操作Java堆中的对象,Java虚拟机只规定了虚拟机栈的引用有一个指向对象的引用, 但是并没有规定如何定位这个对象,所以一般有两种方法 1、引用指向句柄 如果是此种做法,那么虚拟机在Java堆中开辟一个空间(句柄池)用来存放句柄,句柄中有指向对象实例的指针和指向对象元数据(java.lang.Class)的指针 |
JSON Code
1
2 |
2、引用直接指向对象
引用直接指向对象实例,在对象实例中有一个指向对象元数据的指针 |
JSON Code
1
2 3 4 5 6 7 8 9 |
总结:方法1
优点: 指向对象的引用保存的内容不会变,当对象移动时只需要修改句柄池中的引用 缺点:访问对象要访问两次指针 方法2 优点: 访问对象直接去访问效率要高 缺点: 在对象移动时要修改对象体中的引用指向 |