1、pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.atguigu</groupId><artifactId>data-structure-alg</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>demo01-array</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.17</version></dependency></dependencies></project>
2、ClassLayout.parseInstance(new Object()).toPrintable()
//查看对象在内存中是如何保存的?Object o = new Object();//获取对象的布局转为可以输出的字符串 打印System.out.println(ClassLayout.parseInstance(o).toPrintable());
java.lang.Object object internals: OFF SZ TYPE DESCRIPTION VALUE0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)8 4 (object header: class) 0x00000d5812 4 (object alignment gap) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
这段代码是用来打印Java对象的内部布局信息的。具体来说,它使用了
ClassLayout
类的parseInstance
方法来解析一个Object
实例的布局,并打印出相应的信息。输出中的内容描述了对象的内存布局:
OFF
和SZ
分别表示对象在内存中的偏移量和大小。TYPE DESCRIPTION
提供了对象的类型描述。VALUE
是与每个字段关联的值。从输出中可以看到:
- 对象头(object header)的 标记(mark)字段位于偏移量0,大小为8字节。synchronized加锁:必须通过对象加锁
- 对象头的类(class)字段位于偏移量8,大小为4字节。类模板对象的引用,类模板存在方法区(元空间MetaSpace)中,对象可以通过该位置的地址获取到类模板对象
- 对象头后面有一个4字节的空隙,可能是用于对齐。
- 实例大小(Instance size)为16字节。
- 内部空间损失(Space losses)为0字节,外部空间损失为4字节。
需要注意的是,输出的信息可能因JVM的实现和版本而有所不同。因此,如果你在不同的JVM或不同的Java版本上运行此代码,可能会得到不同的输出结果。
3、ClassLayout.parseInstance(new int[5]).toPrintable()
//int类型数组的值占的内存:4*5=20byteint[] ints = new int[5];System.out.println(ClassLayout.parseInstance(ints).toPrintable());
[I object internals: OFF SZ TYPE DESCRIPTION VALUE0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)8 4 (object header: class) 0x000065f812 4 (array length) 516 20 int [I.<elements> N/A36 4 (object alignment gap) Instance size: 40 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
4、 ClassLayout.parseInstance(new long[5]).toPrintable()
//long类型数组的值占的内存:8*5=40bytelong[] longs = new long[5];System.out.println(ClassLayout.parseInstance(longs).toPrintable());
[J object internals: OFF SZ TYPE DESCRIPTION VALUE0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)8 4 (object header: class) 0x0000116012 4 (array length) 516 40 long [J.<elements> N/A Instance size: 56 bytes Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
5、ClassLayout.parseInstance(new LinkedList<>()).toPrintable()
LinkedList<Integer> list = new LinkedList<>();Collections.addAll(list, 1, 2, 3, 4, 5);System.out.println(ClassLayout.parseInstance(list).toPrintable());
java.util.LinkedList object internals: OFF SZ TYPE DESCRIPTION VALUE0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)8 4 (object header: class) 0x001ef21812 4 int AbstractList.modCount 516 4 int LinkedList.size 520 4 java.util.LinkedList.Node LinkedList.first (object)24 4 java.util.LinkedList.Node LinkedList.last (object)28 4 (object alignment gap) Instance size: 32 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
6、object alignment gap
- 在Java中,对象的内存布局和对齐与C/C++中的情况略有不同,但"gap"的概念仍然存在。
- 在Java中,"gap"通常指的是在对象的内存布局中,为了满足对齐规则而产生的未使用的空间。这与C/C++中的情况类似,但Java的内存模型和垃圾回收机制与C/C++有所不同,因此对象的内存布局和对齐方式也有所不同。
- 在Java中,对象的内存布局通常包括对象头、实例数据和对齐填充。对象头包含对象的元数据信息,实例数据包含对象的字段值,对齐填充是为了满足JVM的对齐规则而产生的未使用的空间。
- 需要注意的是,Java中的对象对齐规则和填充方式可能会因JVM的实现和版本而有所不同。因此,在不同的JVM或不同的Java版本上,同一个对象的内存布局和对齐方式可能会有所不同。
7、对象头的作用
在Java中,对象头(Object Header)是Java对象在内存中的元数据部分,它记录了对象的元信息,如类的元信息、哈希码、GC标记等。对象头的作用主要有以下几个方面:
- 记录类的元信息:对象头中存储了对象的类信息,包括类的元数据、类加载器信息等。这些信息用于确定对象的类型和行为。
- 存储哈希码:对象头中存储了对象的哈希码,用于支持Java的哈希表实现。哈希码是对象在哈希表中的索引,用于快速查找和比较对象。
- GC标记:对象头中存储了GC标记信息,用于垃圾回收器跟踪和管理对象。当垃圾回收器需要回收内存时,会通过GC标记来判断哪些对象需要被回收。
需要注意的是,Java中的对象头是JVM内部管理的,对于Java程序来说是透明的。程序员不需要直接操作对象头,只需要关注对象的实例数据即可。