JOL(Java Object Layout)是一个Java对象布局分析工具。它可以帮助开发人员分析Java对象在内存中的布局,查看对象的成员变量的大小、偏移量、对齐方式等信息。JOL是基于OpenJDK的HotSpot虚拟机实现的,可以在程序运行时动态分析对象布局,非常适合用于Java性能优化和调试。
JOL工具可以执行以下任务:
- 显示Java对象的内部布局,包括对象头、实例数据、对齐填充等信息。
- 显示对象成员的大小、偏移量、类型等信息。
- 显示对象成员的对齐方式和填充情况。
- 显示对象的哈希码、类名等信息。
- 支持解析Java对象的压缩指针(Compressed Oops)格式。
使用JOL工具可以帮助开发人员更好地理解Java对象的内部结构和存储方式,从而优化Java程序的性能,避免内存泄漏和其他问题。JOL工具非常易于使用,只需要在项目中引入JOL的依赖项,然后在代码中调用JOL的API即可。
maven引入
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.10</version>
</dependency>
复制代码
使用方法
// 查看对象内部信息
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
复制代码
测试代码1
public class JolTest {
public static void main(String[] args) {
Object obj = new Object();
// 查看对象内部信息
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
}
复制代码
输出结果
其中,每一行输出表示一个成员变量或对象头的信息,具体含义如下:
- OFFSET:成员变量或对象头的偏移量,相对于Java对象的起始地址。
- SIZE:成员变量或对象头的大小,以字节为单位。
- TYPE:成员变量或对象头的类型,包括Java基本类型和对象类型。
- DESCRIPTION:成员变量或对象头的描述信息,包括成员变量的名称和类型。
- VALUE:成员变量或对象头的值,以16进制表示。对于对象头,包括Mark Word和Klass Pointer等信息。
- Instance size:对象实例的大小,包括对象头、实例变量和对齐填充的总大小。
- Space losses:对象实例中的空间损失,包括对象内部的空间损失和对象外部的空间损失。
需要注意的是,JOL工具输出的信息可能会因不同的JVM实现和不同的JVM参数而有所不同,因此在使用JOL工具时需要注意选择合适的环境和参数。
测试代码2
public class JolTest {
public static void main(String[] args) {
Object obj = new Test();
// 查看对象内部信息
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
}
class Test{
private long p;
}
复制代码
测试代码3
public class JolTest {
public static void main(String[] args) {
Object obj = new Test();
// 查看对象内部信息
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
}
class Test{
private long p;
private byte p1;
private short p2;
}
复制代码
为什么对象实例的大小(Instance size)还是24?
因为alignment/padding gap进行了字节的对齐填充,如果其他变量比如byte和short加起来没有超过对齐填充的大小还是算加上了对齐填充的大小。
DESCRIPTION的“alignment/padding gap”是什么意思?
在JOL工具的输出结果中,每个成员变量或对象头的信息前面都有一个"DESCRIPTION"字段,它包含成员变量或对象头的名称和类型等描述信息。其中,如果成员变量或对象头的偏移量不是8的倍数,JOL会在该字段后面显示一个"alignment/padding gap"字段,表示在该成员变量或对象头后面添加了多少字节的对齐填充。
对齐填充是指在成员变量或对象头之间添加一些字节,以保证它们的偏移量都是8的倍数。这样做的原因是为了提高访问成员变量或对象头的效率,因为访问8字节对齐的变量比非对齐变量更快。对齐填充的大小取决于成员变量或对象头的大小和偏移量等因素,因此可能会在输出结果中出现"alignment/padding gap"信息。
需要注意的是,对齐填充在内存中不占用任何有意义的数据,只是为了对齐而填充的字节。因此,对齐填充的大小可能会影响Java对象的内存占用大小,但不会影响对象的实际内容。
java中各个类型都占用多少个字节?
以下是Java中各个基本数据类型的大小(占用字节数):
- byte:1个字节(8位)
- short:2个字节(16位)
- int:4个字节(32位)
- long:8个字节(64位)
- float:4个字节(32位)
- double:8个字节(64位)
- char:2个字节(16位)
- boolean:1个字节(8位),但是实际上只使用其中1个bit,取值为true或false。
需要注意的是,Java中的基本数据类型大小和具体实现有关,不同的JVM实现可能会有所不同。此外,Java中的引用类型(如Object、String等)大小取决于具体实现和对象的内容,因此无法给出固定大小。
作者:朝夕时
链接:https://juejin.cn/post/7226357340060647485