本文主要基于周志明老师的《深入理解Java虚拟机》。
[toc]
HotSpot Java Object Layout
本次讨论的是HotSpot虚拟机中Java实例在内存中的布局。
内存结构
普通对象
对象在内存中的存储布局可以分为三个部分:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。
Header
Header由MarkWord和ClassPointer组成。
MarkWord在32位JVM中的长度是4字节,在64位JVM中长度是8字节。
MarkWord内存布局
*_执行过IdentityHashCode的对象上不了偏向锁。
ClassPointer是元数据类型指针,可以通过-XX:+UseCompressedClassPointers来压缩成4字节。
Instance Data
Instance Data储存着对象的属性。
- byte 1字节、short 2字节、int 4字节、long 8字节
- float 4字节、double 8字节
- char 2字节
- boolean 1字节
- 引用类型
- XX:+UseCompressedOops 为4字节 不开启为8字节
- OOps:Ordinary Object Pointers
Padding
Padding将对象在内存中的大小填充至n*8字节。这也是CompressedOops的原理由来,通过将内存地址除8可以得到压缩后的地址,使用时乘8还原回来就行,通过这种方式在4字节的空间中可以表示32g的内存地址。
数组对象
- Markword
- ClassPointer
- 数组长度(4字节)
- 数组数据
- 参考普通对象
- Padding
Hotspot内存压缩规则(64位机)
- 4G以下,直接采用32位。
- 4G - 32G,默认开启内存压缩 ClassPointers Oops。
- 32G,压缩无效,使用64位。
+UseCompressedOops时自动开启+UseCompressedClassPointers。
www.cnblogs.com/yaoyuanecho…
这篇博客详细讨论了+UseCompressedOops和+UseCompressedClassPointers之间的开启关系。
Compressed Class Space
通过jstat -gc查看gc分区信息的时候,会看到一个CCSC和CCSU,这便是Compressed Class Space大小和已使用大小。Compressed Class Space中存放了Klass对象,就是类的元信息。
如果关闭UseCompressedClassPointers,那么便不会生成Compressed Class Space。
通过OpenJDK.Jol观察对象内存布局
导入依赖:
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
代码如下:
public class A {
private int x;
private String y;
public static void main(String[] args) {
ClassLayout classLayout = ClassLayout.parseClass(A.class);
System.out.println(classLayout.toPrintable());
}
}
输出如下:
jol.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 12 (object header) N/A
12 4 int A.x N/A
16 4 java.lang.String A.y N/A
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total