实验查看 Java 对象布局
前言
我们知道,对于普通的 Java
对象(非数组、非列表、非集合、非 Map 等对象),其内存布局由对象头
、实例数据
、对象补齐
三部分组成,其布局如下图所示:
其中,对象头
由 MarkWork
及 ClassPointer
组成。
MarkWork
用于存放 hashCode
、GC
信息和锁信息,在 64
位 JVM
中占用 8
个字节(无论是否开启压缩);
ClassPointer
用于存放对象类型,在 64
位 JVM
中,不开启类型指针压缩占用 8
个字节,开启类型指针压缩后占用 4
个字节,默认开启类型指针压缩(-XX:+UseCompressedClassPointers);
下面通过实验的方式查看 Java
对象的布局。
环境准备
本次实验在 Debian
64 位操作系统中进行,使用 JDK
版本如下:
shaw@shaw-pc:~$ java -version
java version "1.8.0_211"
Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)
项目需要使用 JOL
工具,JOL
工具全称 Java Object Layout
,用于分析 JVM
中的对象布局;
代码准备
-
引入
Maven
依赖<dependency> <groupId>org.openjdk.jol</groupId> <artifactId>jol-core</artifactId> <version>0.9</version> </dependency>
-
UserInfo.java
package com.shawearn.jvm.object.layout.model; /** * 用户信息; */ public class UserInfo { private Integer userId; private String name; // 此处省略对应 get/set 方法; }
-
Main.java
package com.shawearn.jvm.object.layout; import com.shawearn.jvm.object.layout.model.UserInfo; import org.openjdk.jol.info.ClassLayout; public class Main { public static void main(String[] args) { Object object = new Object(); System.out.println("========== Object =========="); System.out.println(ClassLayout.parseInstance(object).toPrintable()); System.out.println("========== Object =========="); UserInfo userInfo = new UserInfo(); System.out.println("========== userInfo =========="); System.out.println(ClassLayout.parseInstance(userInfo).toPrintable()); System.out.println("========== userInfo =========="); } }
-
将上面代码打包成 jar 包,包文件命名:
object-layout.jar
测试
1. 开启指针压缩(默认开启)
64
位的 JDK
默认会开启类指针压缩和对象指针压缩;
运行命令
# 运行 object-layout.jar 文件;
# 其中 -XX:+PrintCommandLineFlags 表示输出 JVM 采用的自动优化参数,此参数只是方便用户查看,运行时可不带此参数;
java -XX:+PrintCommandLineFlags -jar object-layout.jar
运行结果
-XX:InitialHeapSize=32652736 -XX:MaxHeapSize=522443776 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
========== Object ==========
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 09 00 00 00 (00001001 00000000 00000000 00000000) (9)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
========== Object ==========
========== userInfo ==========
com.shawearn.jvm.object.layout.model.UserInfo object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) f5 02 01 20 (11110101 00000010 00000001 00100000) (536937205)
12 4 java.lang.Integer UserInfo.userId null
16 4 java.lang.String UserInfo.name null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
========== userInfo ==========
说明
从上面的执行结果可以看到 JVM
的自动优化参数包含了如下两个:
-XX:+UseCompressedClassPointers
表示开启类指针压缩;
-XX:+UseCompressedOops
表示开启对象指针压缩;
可以看到 Object
与 UserInfo
两个类对象大小分别为 16
bytes 和 24
bytes。
接下分析开启压缩时 Object
与 UserInfo
两个类对象的内存信息。
Object
从上面的运行结果可知:
- object 对象头(object header)占用 4 + 4 + 4 =12 个字节;
- object 没有实例变量,所以实例数据占用 0 字节;
- 由于 12 + 0 = 12,无法被 8 整除,所以对象补齐 4 字节(loss due to the next object alignment)。
因此整个 object 对象内存占用 12 + 0 + 4 = 16 字节;
UserInfo
由运行结果可知:
- userInfo 对象头(object header)占用 4 + 4 + 4 =12 个字节;
- 成员变量 (java.lang.Integer UserInfo.userId) 占用 4 个字节;
- 成员变量 (java.lang.String UserInfo.name) 占用 4 个字节;
- 由于 12 + 4 + 4 = 20 无法被 8 整除,所以对象补齐 4 字节(loss due to the next object alignment)。
因此整个 userInfo 对象内存占用 12 + 4 + 4 + 4 = 24 字节;
2. 关闭指针压缩
使用 -XX:-UseCompressedClassPointers
与 -XX:-UseCompressedOops
两个参数分别关闭类指针压缩及对象指针压缩;
运行命令
# 运行 object-layout.jar 文件;
# 其中 -XX:+PrintCommandLineFlags 表示输出 JVM 采用的自动优化参数,此参数只是方便用户查看,运行时可不带此参数;
# -XX:-UseCompressedClassPointers 关闭类指针压缩;
# -XX:-UseCompressedOops 关闭对象指针压缩;
java -XX:+PrintCommandLineFlags -XX:-UseCompressedClassPointers -XX:-UseCompressedOops -jar object-layout.jar
运行结果
-XX:InitialHeapSize=32652736 -XX:MaxHeapSize=522443776 -XX:+PrintCommandLineFlags -XX:-UseCompressedClassPointers -XX:-UseCompressedOops -XX:+UseParallelGC
========== Object ==========
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 09 00 00 00 (00001001 00000000 00000000 00000000) (9)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 00 1c 46 48 (00000000 00011100 01000110 01001000) (1212554240)
12 4 (object header) 83 7f 00 00 (10000011 01111111 00000000 00000000) (32643)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
========== Object ==========
========== userInfo ==========
com.shawearn.jvm.object.layout.model.UserInfo object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 90 21 c1 48 (10010000 00100001 11000001 01001000) (1220616592)
12 4 (object header) 83 7f 00 00 (10000011 01111111 00000000 00000000) (32643)
16 8 java.lang.Integer UserInfo.userId null
24 8 java.lang.String UserInfo.name null
Instance size: 32 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
========== userInfo ==========
说明
从上面的执行结果可以看到已经关闭类指针压缩和对象指针压缩;
可以看到 Object
与 UserInfo
两个类对象大小分别为 16
bytes 和 32
bytes。
乍眼一看,压缩前后 Object
对象的内存占用都是 16
字节,似乎没什么区别。其实不然,接下分析开启压缩时 Object
与 UserInfo
两个类对象的内存信息。
Object
由运行结果可知:
- object 对象头(object header)占用 4 + 4 + 4 + 4 =16 个字节;
- object 没有实例变量,所以实例数据占用 0 字节;
- 由于 16 + 0 = 16,可以被 8 整除,所以无需对象补齐。
因此整个 object 对象内存占用 16 + 0 = 16 字节;
UserInfo
由运行结果可知:
- userInfo 对象头(object header)占用 4 + 4 + 4 + 4 =16 个字节;
- 成员变量 (java.lang.Integer UserInfo.userId) 占用 8 个字节;
- 成员变量 (java.lang.String UserInfo.name) 占用 8 个字节;
- 由于 16 + 8 + 8 = 32,可以被 8 整除,所以无需对象补齐。
因此整个 userInfo 对象内存占用 16 + 8 + 8 = 32 字节;
本文地址:https://blog.csdn.net/shawearn1027/article/details/107160537
上一篇: 【Oracle】--SQL优化