java
标准化、规范化
java代码风格
【目录】java
编程-java8
编程-java9
编程-java-见过的异常
gradle
编程-java21
编程-java23
编程-java17
编程-java11
【目录】java-web-其它框架
java-vertx
quarkus
javalin
solon
Helidon
【目录】spring家族
spring
springcloud + nacos
consul
springboot启动流程
springboot使用及原理
springcloud
优化springboot
【java高级】
java-多线程-问题记录
java高级-ArrayList
java高级-HashMap
jdk源码解析-TreeMap红黑树
java对象占用多少字节
juc(并发)
ThreadPoolExecutor中ctl变量的理解
ThreadPoolExecutor分析
JVM(java虚拟机)
jvm学习路线
jvm
Java启动参数
debug
java-debug-arthas
java-debug-jdb
高并发/高性能/高可用
设计代码或编写代码时应该考虑的
如何发现系统中的瓶颈?
场景分析
mysql
mysql explain
mysql主从
mysql常见异常
方法论
工作中遇到的问题记录
代码优化
学习的思路
产品
本文档使用 MrDoc 发布
-
+
首页
java对象占用多少字节
## Java 对象模型 HotSpot JVM 使用名为 oops (Ordinary Object Pointers) 的数据结构来表示对象。这些 oops 等同于本地 C 指针。 instanceOops 是一种特殊的 oop,表示 Java 中的对象实例。 在 Hotspot VM 中,对象在内存中的存储布局分为 3 块区域: - 对象头(Header) - 实例数据(Instance Data) - 对齐填充(Padding) 对象头又包括三部分:MarkWord、元数据指针、数组长度。 - MarkWord:用于存储对象运行时的数据,好比 HashCode、锁状态标志、GC分代年龄等。这部分在 64 位操作系统下占 8 字节,32 位操作系统下占 4 字节。 - 指针:对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪一个类的实例。这部分就涉及到指针压缩的概念,在开启指针压缩(-XX:+UseCompressedClassPointers )的状况下占 4 字节,未开启状况下占 8 字节。 - 数组长度:这部分只有是数组对象才有,若是是非数组对象就没这部分。这部分占 4 字节。 实例数据就不用说了,用于存储对象中的各类类型的字段信息(包括从父类继承来的)。 关于对齐填充,Java 对象的大小默认是按照 8 字节对齐,也就是说 Java 对象的大小必须是 8 字节的倍数。若是算到最后不够 8 字节的话,那么就会进行对齐填充。  ## 基础对象占用存储空间 Java 基础对象在内存中占用的空间如下: | 类型 | 占用空间(byte) | | --- | --- | | boolean | 1 | | byte | 1 | | short | 2 | | char | 2 | | int | 4 | | float | 4 | | long | 8 | | double | 8 | JOL(Java Object Layout)是用于分析 JVM 中对象布局方案的微型工具箱。这些工具大量使用 Unsafe、JVMTI 和 Serviceability Agent (SA) 来解码实际的 对象布局、占用空间和引用。这使得 JOL 比其他依赖堆转储、规范假设等的工具更准确。 ```xml <dependency> <groupId>org.openjdk.jol</groupId> <artifactId>jol-core</artifactId> <version>0.17</version> </dependency> ``` ### Integer占用多少字节 由于现在基本都是 64 位的虚拟机,所以后面的讨论都是基于 64 位虚拟机。 ```java ClassLayout classLayout = ClassLayout.parseInstance(4); System.out.println(classLayout.toPrintable()); ``` #### jvm参数:`-XX:+UseCompressedClassPointers` 执行结果 ```text java.lang.Integer object internals: OFF SZ TYPE DESCRIPTION VALUE 0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0) 8 4 (object header: class) 0x00025938 12 4 int Integer.value 4 Instance size: 16 bytes Space losses: 0 bytes internal + 0 bytes external = 0 bytes total ``` #### jvm参数:`-XX:-UseCompressedClassPointers` ```text java.lang.Integer object internals: OFF SZ TYPE DESCRIPTION VALUE 0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0) 8 8 (object header: class) 0x000001ff6316fd80 16 4 int Integer.value 4 20 4 (object alignment gap) Instance size: 24 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total ``` ## 一个空对象占用多少字节 ```java publci class EmptyObject { } ``` 理论上一个空对象占用内存大小只有对象头信息,对象头占 8+4=12 个字节。那么 EmptyObject.class 应该占用的存储空间就是 12 字节,考虑到 8 字节的对齐填充,那么会补上 4 字节填充到 8 的 2倍,总共就是 16字节。怎么验证我们的结论呢?JDK 提供了一个工具,JOL 全称为 Java Object Layout,是分析 JVM 中对象布局的工具,该工具大量使用了 Unsafe、JVMTI 来解码布局情况。下面我们就使用这个工具来获取一个 Java 对象的大小。 ```java public class HowManyBytesObjectOccupy { @Test public void testEmptyObject() { ClassLayout classLayout = ClassLayout.parseInstance(new EmptyObject()); System.out.println(classLayout.toPrintable()); } } class EmptyObject { } ``` jvm参数:`-XX:-UseCompressedClassPointers` ```text javas.advanced.EmptyObject object internals: OFF SZ TYPE DESCRIPTION VALUE 0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0) 8 8 (object header: class) 0x0000025eb9b60598 Instance size: 16 bytes Space losses: 0 bytes internal + 0 bytes external = 0 bytes total ``` jvm参数:`-XX:+UseCompressedClassPointers` ```text javas.advanced.EmptyObject object internals: OFF SZ TYPE DESCRIPTION VALUE 0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0) 8 4 (object header: class) 0x0101a140 12 4 (object alignment gap) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total ``` ## 测试其它 ```java class FullObject { private byte b; private char type; private short age; private int no; private float weight; private double price; private long id; private boolean flag; private String str; private LocalDateTime dateTime; private String[] strs; private List<String> strList; } @Test public void testFullObject() { ClassLayout classLayout = ClassLayout.parseInstance(new FullObject()); System.out.println(classLayout.toPrintable()); } ``` 未指定jvm参数`-XX:+UseCompressedClassPointers`,但默认是开户压缩。 结果是 ```text javas.advanced.FullObject object internals: OFF SZ TYPE DESCRIPTION VALUE 0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0) 8 4 (object header: class) 0x0101a140 12 4 int FullObject.no 0 16 8 double FullObject.price 0.0 24 8 long FullObject.id 0 32 4 float FullObject.weight 0.0 36 2 char FullObject.type 38 2 short FullObject.age 0 40 1 byte FullObject.b 0 41 1 boolean FullObject.flag false 42 2 (alignment/padding gap) 44 4 java.lang.String FullObject.str null 48 4 java.time.LocalDateTime FullObject.dateTime null 52 4 java.lang.String[] FullObject.strs null 56 4 java.util.List FullObject.strList null 60 4 (object alignment gap) Instance size: 64 bytes Space losses: 2 bytes internal + 4 bytes external = 6 bytes total ``` 注意有两处padding - 第一处是OFF(OFFSET)为42,原因是后面的字段是4byte,而此处缺少2byte,不能把后面字段的4byte拆开,所以要添加padding。 - 第二处是OFF(OFFSET)为60。全部实例数据后需要padding。
我是张三
2025年3月28日 14:56
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
eblog
Markdown文件
分享
链接
类型
密码
更新密码