一、理论篇

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

java 对象所占内存 java 对象内存大小_数据


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


java 对象所占内存 java 对象内存大小_数据_02

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

数据类型

数据长度

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对象大小

Objectobj=newObject();


开启指针压缩

关闭指针压缩

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 包含实例数据的对象

publicclassObjectWithInstanceData {
  privateinta=10;
  privatedoubleb=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 是

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

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

import org.openjdk.jol.info.ClassLayout;

publicclassObjectWithInstanceData {

    privateinta=10;
    privatedoubleb=10.0d;

    publicstaticvoidmain(String[] args) {
        Objectobj=newObject();
        Stringvalue= ClassLayout.parseInstance(obj).toPrintable();
        System.out.println(value);

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

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

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


java 对象所占内存 java 对象内存大小_android_03


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


java 对象所占内存 java 对象内存大小_Powered by 金山文档_04


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


java 对象所占内存 java 对象内存大小_数据_05


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

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


java 对象所占内存 java 对象内存大小_java_06


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


java 对象所占内存 java 对象内存大小_java 对象所占内存_07


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


java 对象所占内存 java 对象内存大小_数据_08


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