网站首页 > 博客文章 正文
这个问题一般会出现在稍微高端一点的 Java 面试环节。要求面试者不仅对 Java 基础知识熟悉,更重要的是要了解内存模型。
Java 对象模型
在 Hotspot VM 中,对象在内存中的存储布局分为 3 块区域:
- 对象头(Header)
对象头又包括三部分:MarkWord、元数据指针、数组长度。
- MarkWord:用于存储对象运行时的数据,好比 HashCode、锁状态标志、GC分代年龄等。这部分在 64 位操作系统下占 8 字节,32 位操作系统下占 4 字节。
- 元数据指针:对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪一个类的实例。这部分就涉及到指针压缩的概念,在开启指针压缩的状况下占 4 字节,未开启状况下占 8 字节。
- 数组长度:这部分只有是数组对象才有,若是是非数组对象就没这部分。这部分占 4 字节。
- 实例数据(Instance Data)
用于存储对象中的各类类型的字段信息(包括从父类继承来的)
- 对齐填充(Padding)
Java 对象的大小默认是按照 8 字节对齐,也就是说 Java 对象的大小必须是 8 字节的倍数
为何非要进行 8 字节对齐呢?
由于 CPU 进行内存访问时,一次寻址的指针大小是 8 字节,正好也是 L1 缓存行的大小。如果不进行内存对齐,则可能出现跨缓存行的情况,这叫做 缓存行污染。
在Hotspot 虚拟机文档 “oops/oop.hp” 有对 Markword 字段的定义:
我们主要关注 normal object, 这种类型的 Object 的 Markword 一共是 8 个字节(64位),其中 25 位暂时没有使用,31 位存储对象的 hash 值(注意这里存储的 hash 值对根据对象地址算出来的 hash 值,不是重写 hashcode 方法里面的返回值),中间有 1 位没有使用,还有 4 位存储对象的 age(分代回收中对象的年龄,超过 15 晋升入老年代),最后三位表示偏向锁标识和锁标识,主要就是用来区分对象的锁状态(未锁定,偏向锁,轻量级锁,重量级锁)
biased object 的对象头 Markword 前 54 位来存储持有该锁的线程 id,这样就没有空间存储 hashcode了,所以 对于没有重写 hashcode 的对象,如果 hashcode 被计算过并存储在对象头中,则该对象作为同步锁时,不会进入偏向锁状态,因为已经没地方存偏向 thread id 了,所以我们在选择同步锁对象时,最好重写该对象的 hashcode 方法,使偏向锁能够生效。
基本类型占用存储空间和指针压缩
基础对象占用存储空间
Java 基础对象在内存中占用的空间如下:
类型 | 占用空间(byte) |
boolean | 1 |
byte | 1 |
short | 2 |
char | 2 |
int | 4 |
float | 4 |
long | 8 |
double | 8 |
另外,引用类型在 32 位系统上每个引用对象占用 4 byte,在 64 位系统上每个引用对象占用 8 byte。
Java 中基础数据类型是在栈上分配还是在堆上分配?
我们继续深究一下,基本数据类占用内存大小是固定的,那具体是在哪分配的呢,是在堆还是栈还是方法区?大家不妨想想看! 要解答这个问题,首先要看这个数据类型在哪里定义的,有以下三种情况。
- 如果在方法体内定义的,这时候就是在栈上分配的
- 如果是类的成员变量,这时候就是在堆上分配的
- 如果是类的静态成员变量,在方法区上分配的
指针压缩
引用类型在 64 位系统上占用 8 个字节,虽然一个并不大,但是耐不住多。
所以为了解决这个问题,JDK 1.6 开始 64 bit JVM 正式支持了 -XX:+UseCompressedOops (需要jdk1.6.0_14) ,这个参数可以压缩指针。
启用 CompressOops 后,会压缩的对象包括:
- 对象的全局静态变量(即类属性);
- 对象头信息:64 位系统下,原生对象头大小为 16 字节,压缩后为 12 字节;
- 对象的引用类型:64 位系统下,引用类型本身大小为 8 字节,压缩后为 4 字节;
- 对象数组类型:64 位平台下,数组类型本身大小为 24 字节,压缩后 16 字节。
当然压缩也不是万能的,针对一些特殊类型的指针 JVM是不会优化的。 比如:
- 指向非 Heap 的对象指针
- 局部变量、传参、返回值、NULL指针。
验证
我们来 new 一个空对象:
class ObjA {
}
理论上一个空对象占用内存大小只有对象头信息,对象头占 12 个字节。那么 ObjA.class 应该占用的存储空间就是 12 字节,考虑到 8 字节的对齐填充,那么会补上 4 字节填充到 8 的 2倍,总共就是 16字节。怎么验证我们的结论呢?JDK 提供了一个工具,JOL 全称为 Java Object Layout,是分析 JVM 中对象布局的工具,该工具大量使用了 Unsafe、JVMTI 来解码布局情况。
首先引入 Maven 依赖:
Copy<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.14</version>
</dependency>
public class ObjSiZeTest {
public static void main(String[] args) {
ClassLayout classLayout = ClassLayout.parseInstance(new ObjA());
System.out.println(classLayout.toPrintable());
}
}
class ObjA {
}
运行结果:
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
再来测试一下包含int、double、Integer数据的类内存大小是多少?
class ObjA {
private int i;
private double d;
private Integer io;
}
int 类型占 4 个字节 ,double 类型占 8 个字节,Integer 是引用类型,64 位系统占 4 个字节。一共 16 个字节。加上对象头 12 字节,显然不够 8 的倍数,所以还得 4 字节的填充,加起来就是 32 字节。
运行结果:
Instance size: 32 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
总结
Java对象内存部分如下图:[注:数组对象头里多了一个数组长度]
- 上一篇: 4种方法教你如何查看java对象所占内存大小
- 下一篇: Java项目中高效处理大数据量查询的方法
猜你喜欢
- 2025-05-14 JAVA程序员自救之路——Elasticsearch向量搜索
- 2025-05-14 探秘Java程序的“内存大爆炸”:JVM内存溢出问题排查
- 2025-05-14 Java 探秘:如何找出数组中重复的数字
- 2025-05-14 线上问题解决:java内存溢出问题分析,定位及解决
- 2025-05-14 Java虚拟机内存管理深度解读
- 2025-05-14 Java程序内存泄漏问题优化全攻略
- 2025-05-14 Jprofile解析dump文件使用详解
- 2025-05-14 Java中常见的内存泄漏场景解析
- 2025-05-14 Java内存泄漏暗杀指南!3招揪出8G“内存刺客”(附排查神器)
- 2025-05-14 Java内存分析工具——jmap
你 发表评论:
欢迎- 367℃用AI Agent治理微服务的复杂性问题|QCon
- 358℃初次使用IntelliJ IDEA新建Maven项目
- 356℃手把手教程「JavaWeb」优雅的SpringMvc+Mybatis整合之路
- 351℃Maven技术方案最全手册(mavena)
- 348℃安利Touch Bar 专属应用,让闲置的Touch Bar活跃起来!
- 346℃InfoQ 2024 年趋势报告:架构篇(infoq+2024+年趋势报告:架构篇分析)
- 345℃IntelliJ IDEA 2018版本和2022版本创建 Maven 项目对比
- 342℃从头搭建 IntelliJ IDEA 环境(intellij idea建包)
- 最近发表
- 标签列表
-
- powershellfor (55)
- messagesource (56)
- aspose.pdf破解版 (56)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- vue回到顶部 (57)
- qcombobox样式表 (68)
- vue数组concat (56)
- tomcatundertow (58)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)