【学习笔记】子牙教会我计算Java对象大小

硬核子牙公众号原文:你知道如何计算Java的对象大小吗

本文基于子牙老师的讲解,用来记录本人的理解。

一、理论篇

本文计算的是Java对象在 堆区 的大小。学习和掌握该知识,有助于分析“应用系统的堆到底该设置为多大?”的问题。

接着,我整理了一张思维导图,来对对象结构中的各部分大小进行解释:

关于实例数据区域数据大小如下表所示:

数据类型 数据长度
boolean 1B
byte 1B
char 2B
int 4B
float 4B
long 8B
double 8B
引用类型 (开启指针压缩)4B
(关闭指针压缩)8B

二、猜想篇

结合第一章《理论篇》的知识,猜想一下,在64位虚拟机下,Java对象的大小。

目前,主流的服务器基本上都使用的是64位Java虚拟机,因此,接下来计算Java对象大小时,都以此为前提。(不考虑32位虚拟机的情况)

2.1 Object对象大小

Object obj = new Object();
开启指针压缩 关闭指针压缩
Mark Word 8B 8B
Klass Pointer 4B 8B
实例数据 0B 0B
对齐填充 4B 0B
合计 16B 16B

在64位Java虚拟机下,Mark Word 都为 8B;

开启指针压缩时,因为 8B + 4B + 0B + 0B = 12B,不符合 JVM 所有对象按 8 字节对齐的规则。因此,对象大小扩展到 16B,就可以被 8 整除了。此时,对齐填充的大小等于 4B。

2.2 包含实例数据的对象

public class ObjectWithInstanceData {
  private int a = 10;
  private double b = 10.0d;
}
开启指针压缩 关闭指针压缩
Mark Word 8B 8B
Klass Pointer 4B 8B
实例数据 12B 12B
对齐填充 0B 4B
合计 24B 32B

2.3 数组对象

int[] array = {1,2,3};
开启指针压缩 关闭指针压缩
Mark Word 8B 8B
Klass Pointer 4B 8B
数组长度 4B 4B
对齐填充(数组对象才有的) 0B 4B
实例数据 12B 12B
对齐填充 4B 4B
合计 32B 40B

三、验证篇

3.1 指针压缩的 JVM 参数

指针压缩的 JVM 参数:

# 开启指针压缩(JVM默认开启的)
-XX:+UseCompressedOops
# 关闭指针压缩
-XX:-UseCompressedOops

3.2 借助 jol-core

这是在代码中打印对象大小的方法。在 Maven 项目的 pom.xml 中引入依赖:

<dependency>
      <groupId>org.openjdk.jol</groupId>
      <artifactId>jol-core</artifactId>
      <version>0.16</version>
</dependency>

打印对象大小的 API 是

String value = ClassLayout.parseInstance(obj).toPrintable();
System.out.println(value);

我索性一口气都打印出来:

import org.openjdk.jol.info.ClassLayout;

public class ObjectWithInstanceData {

    private int a = 10;
    private double b = 10.0d;

    public static void main(String[] args) {
        Object obj = new Object();
        String value = ClassLayout.parseInstance(obj).toPrintable();
        System.out.println(value);

        obj = new ObjectWithInstanceData();
        value = ClassLayout.parseInstance(obj).toPrintable();
        System.out.println(value);

        obj = new int[]{1,2,3};
        value = ClassLayout.parseInstance(obj).toPrintable();
        System.out.println(value);
    }
}

开启指针压缩的 Object 对象结构:

开启指针压缩的 ObjectWithInstanceData 对象结构:

开启指针压缩的 int 数组对象结构:

(array length) 和 (alignment/padding gap) 的 OFFSET 和 SZ 相同,占据同一块内存,因此也可以说是对齐字节为 0

关闭指针压缩的 Object 对象结构:

关闭指针压缩的 ObjectWithInstanceData 对象结构:

关闭指针压缩的 int 数组对象结构:

(array length) 和 (alignment/padding gap) 的 OFFSET 相同,从内存相同位置开始,(alignment/padding gap) SZ 比 (array length) SZ 多 4 个字节,因此也可以说是对填充齐字节为 4。

posted @ 2022-08-01 10:19  极客子羽  阅读(794)  评论(0编辑  收藏  举报