## 对象的内存布局
在HotSpot虚拟机中,对象的内存布局分为以下3个区域:
* 对象头
* 实例数据
* 对齐填充
![](https://img.kancloud.cn/ce/c1/cec1a91e96673b1c679c0b6562b621f8_1938x1098.png)
### 对象头
对象头包含Mark Word和类型指针2个部分。如果是数组对象,则有一部分存储数组的长度。
Mark Word中存储:
* 哈希吗(HashCode)
* GC分代年龄
* 锁状态标志
* 线程持有的锁
* 偏向线程ID
* 偏向时间戳
### 类型指针
类型指针Klass存储该对象的类对象的内存地址,可以通过该指针知道对象是属于哪个类。
### 实例数据
实例数据部分就是成员变量的值,其中包括父类成员变量和本类成员变量。
### 对齐填充
保证对象内存大小是8字节的倍数,不足的部分按填充对齐。
## 参考资料
* 周志明 * 《深入理解Java虚拟机》
## 对象的创建过程
![](https://img.kancloud.cn/db/e3/dbe3ad439a073dbb1b532a3444320af4_1452x1178.png)
1. 类加载检查
先检查对象的类是否加载,没有加载则先加载类。(类加载完成后就能计算出对象的大小,请参考[Java如何计算对象大小](%E5%A6%82%E4%BD%95%E8%AE%A1%E7%AE%97%E5%AF%B9%E8%B1%A1%E5%A4%A7%E5%B0%8F.md)
2. 内存分配
给对象分配内存,如果使用TLAB,则优先在TLAB空间分配,再在Eden区分配。如果内存规整则使用指针碰撞方式分配内存,不规整则使用空闲列表方式分配内存。
* 指针碰撞
内存规整(说明垃圾回收采用的是标记整理算法),已使用内存和空闲内存分界线上放着一个指针左为分界指示器。只需要将指针移动往空闲内存一端移动对象大小的距离。
* 空闲列表
内存不规整(说明垃圾回收采用的是标记清除算法,有碎片),那么VM必须维护一个列表,记录哪些内存是空闲可用的,分配时从空闲列表中找到一块足够大的内存给对象示例使用。
3. 初始化
* 设置零值
内存分配完成后,虚拟机会将分配到内存的空间都初始化为零值。(不包含对象头)
这也保证了Java代码不赋值初始化就直接使用,程序能访问到这些字段的数据类型对应的零值。
* 设置对象头信息
-- 设置klass指针为对应类对象的地址
-- 对象的hashCode
-- 对象的分代年龄 等
* 执行构造方法`<init>`
执行对象所属类定义的`init`构造方法,完成初始化。
至此,一个可用的对象才算是完全创建出来。
## 对象的访问方式
对象的存储空间是在堆中分配的,但是这个对象的引用(存的是地址)却是在栈中分配的。
Java程序通过栈上的`reference`引用来操作堆上的具体对象。
目前对象的访问方式有句柄访问和直接指针访问方式。
### 句柄访问方式
![](https://img.kancloud.cn/80/ba/80baa5cad3929ee49b449d6b042938a3_1370x702.png)
对象引用内存储的是指向句柄地址,句柄对象中包含对象实例数据指针和类型数据指针。
### 直接指针访问方式
![](https://img.kancloud.cn/55/fa/55fa4fdd18191458b964019ddf68f906_1362x704.png)
对象引用中存储的是对象实例数据指针,再通过对象头里的klass指针找到对象类型数据。
总结:
使用句柄方式访问,优点是对象变化时栈中的reference的值不用改变,存储的是稳定的句柄地址;
而使用直接指针方式访问最大好处就是速度更快,它节省了一次指针定位的时间开销。
HotSpot虚拟机采用直接指针的对象访问方式。
- 面试突击
- Java虚拟机
- 认识字节码
- 000Java发展历史
- 000Macos10.15.7上编译OpenJDK8u
- 001熟悉Java内存区域
- 002熟悉HotSpot中的对象
- 003Java如何计算对象大小
- 004垃圾判定算法与4大引用
- 005回收堆和方法区中对象
- 006垃圾收集算法
- 007HotSpot虚拟机垃圾算法实现篇1
- 007HotSpot虚拟机垃圾算法实现篇2
- 007HotSpot虚拟机垃圾算法实现篇3
- 008垃圾收集器
- 009内存分配与回收策略
- 010Java虚拟机相关工具
- 011调优案例分析
- 012一次IDEA的启动速度调优
- 013类文件Class的结构
- 014熟悉字节码指令
- 015类加载机制(过程)
- 016类加载器
- IDEA的JVM参数
- Java基础
- Java自动装箱与拆箱
- Java基础数据类型
- Java方法的参数传递
- Java并发
- 001走入并行的世界
- 002并行程序基础
- 003熟悉Java内存模型JMM
- 004Java并发之volatile关键字
- 005线程池入门到精通
- 006Java多线程间的同步控制方法
- 007Java维基准测试框架JMH
- 008Java并发容器
- 009Java的线程实现
- 010Java关键字synchronized
- 011一些并行模式的熟悉
- 单例模式和不变模式
- 生产者消费者模式
- Future模式
- 012一些并行算法的熟悉
- 面试总结
- 长亮一面