Java 对象占用内存大小

Java 对象

如果想要了解java对象在内存中的大小,必须先要了解java对象的结构。

HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)

java 对象头

  • Mark Word HotSpot虚拟机的对象头(Object Header)包括两部分信息,第一部分用于存储对象自身的运行时数据, 如哈希值(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等,这部分数据的长度在32位和64位的虚拟机(暂 不考虑开启压缩指针的场景)中分别为32个和64个Bits,官方称它为“Mark Word”。
  • Class Metadata Address 存储该对象的 Class 对象的地址。就是该对象属于那个Class。
  • ArrayList 存储数组的长度。 如果是数组对象才会有此数据。非数组对象没有此数据。

具体对象头占用的大小如下:

长度

内容

说明

32/64 bit

Mark Word

存储对象的 hashCode 或锁信息等

32/64 bit

Class Metadata Address

存储到对象类型数据的指针

32/64 bit

ArrayList

数组的长度(如果当前对象是数组)

从上面表格中,我们可以推断出:

32位系统:

  • 对象头占用:32+32=64bit。 64bit/8=8byte。
  • 数组对象头占用:32+32+32=96bit。 96bit/8=12byte。

64位系统:

对象头占用:64+64=128bit。128bit/8=16byte。 数组对象头占用:64+64+64=192bit。 192bit/8=24byte。

实例数据

实例数据就是,对象中的实例变量。 实例变量类型分为:基本类型和引用类型。

类型

32位系统占用空间

64位系统占用空间

boolean

1 byte

1 byte

byte

1 byte

1 byte

char

2 byte

2 byte

short

2 byte

2 byte

int

4 byte

4 byte

float

4 byte

4 byte

long

8 byte

8 byte

double

8 byte

8 byte

ref

4 byte

8 byte

对齐填充

对象在堆中分配的最新存储单位是8byte。如果存储的数据不够8byte的倍数,则对齐填充够8的倍数个字节。

Java 对象大小分析

下面我们以 64 位的 JDK 进行分析 Java 对象在堆中的占用空间大小

代码示例一

public class StrObj1 {
    private String a;
}
public class StrObj2 {
    private String a;
    private String b;
}
public class StrObj3 {
    private String a;
    private String b;
    private String c;
}
public class StrObj4 {
    private String a;
    private String b;
    private String c;
    private String d;
}
public class NumObj {
    private int a;
    private int b;
    private int c;
    private int d;
}
public class Obj {
    public static void main(String[] args) {
        Obj obj = new Obj();
        StrObj1 s1 = new StrObj1();
        StrObj2 s2 = new StrObj2();
        StrObj3 s3 = new StrObj3();
        StrObj4 s4 = new StrObj4();
        Obj[] arrObj = new Obj[10];
        NumObj num = new NumObj();
                //System.gc()  会出发 FullGC。
        System.gc();
    }
}

运行程序

java -XX:+HeapDumpBeforeFullGC -XX:HeapDumpPath=D:\hprof\test2.hprof -XX:-UseCompressedOops cn.com.infcn.jmat.ObjectAnalyze

启动参数说明:

-XX:+UseCompressedOops 开启指针压缩。(默认开启,该参数对64位虚拟机有用) -XX:-UseCompressedOops 关闭指针压缩。 其它参数具体 JVM 参数解释详见:生成 Heap Dump 的几种方式

因为 System.gc(); 会出发FullGC,配合-XX:+HeapDumpBeforeFullGC 参数,会在 FullGC 前会在生成一个堆dump文件:D:\hprof\test2.hprof

分析dump

本案例,使用 jmat 工具进行分析 dump 文件。

cn.com.infcn.jmat.Obj 对象分析

从图中我们发现 cn.com.infcn.jmat.Obj 对象占用 16 byte 空间。 非数组64位的对象头 占用16字节,而且改对象没有属性,16字节正好也是8的倍数,不需要填充,所以占用堆空间久违16字节。

cn.com.infcn.jmat.StrObj1

图中可以看出 cn.com.infcn.jmat.StrObj1 对象占用 24 byte 空间。

对象头 16 byte 1 个引用类型实例变量 16 + 8 = 24 byte

cn.com.infcn.jmat.StrObj2

图中可以看出 cn.com.infcn.jmat.StrObj1 对象占用 32 byte 空间

对象头 16 byte 2 个引用类型实例变量 16 + 2 * 8 = 32 byte

cn.com.infcn.jmat.StrObj3

图中可以看出 cn.com.infcn.jmat.StrObj1 对象占用 40 byte 空间

对象头 16 byte 3 个引用类型实例变量 16 + 3 * 8 = 40 byte

cn.com.infcn.jmat.StrObj4

图中可以看出 cn.com.infcn.jmat.StrObj1 对象占用 48 byte 空间

对象头 16 byte 4个引用类型实例变量 16 + 4 * 8 = 48 byte

cn.com.infcn.jmat.NumObj

图中可以看出 cn.com.infcn.jmat.NumObj 对象占用 32 byte 空间

4个 int 类型实例变量 16 + 4 * 4 = 32 byte

cn.com.infcn.jmat.Obj[] 数组

图中可以看出 cn.com.infcn.jmat.Obj[] 对象占用 104 byte 空间

数组对象头 24 byte 10 个 Obj 的引用。 24 + 8 * 10 = 104 byte

对象数组中存储的是对象的引用,而不是实际的数据。

代码示例 二

public class BooleanObj1 {
    boolean a;
}

......

public class BooleanObj8 {
    boolean a;
    boolean b;
    boolean c;
    boolean d;
    boolean e;
    boolean f;
    boolean g;
    boolean h;
}
public class BooleanObj9 {
    boolean a;
    boolean b;
    boolean c;
    boolean d;
    boolean e;
    boolean f;
    boolean g;
    boolean h;
    boolean i;
}

以指针非压缩方式执行,然后分析dump。

从图中我们发现 BooleanObj1 和 BooleanObj8 大小一样都是24。 而 BooleanObj9 的大小为32。

BooleanObj1

对象头 16 byte 1 个 boolean 实例变量。

16 + 1 = 17 byte。 因为 17 byte 不是 8 的倍数,需要 对齐填充。 所以BooleanObj1 所占空间为 24 byte。

BooleanObj8

对象头 16 byte 8 个 boolean 实例变量。

16 + 8 = 24 byte。

BooleanObj9

对象头 16 byte 9 个 boolean 实例变量

16 + 9 =25 byte 对齐填充 后为 32 byte

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏来自地球男人的部落格

Python常见用法汇总

此篇主要记录写python遇到的一些常见用法。 1. 正则表达式匹配中文 当我们使用正则表达式匹配字符串中的中文中文时会发现字符串明明有目标串却不能匹配的情况 ...

25750
来自专栏数据分析

char varchar nchar nvarcharar到底有多大区别

首先说明下,ASP.NET MVC系列还在龟速翻译中。 工作好多年,基础知识甚是薄弱,决定以后在coding(cv操作)的时候尽量多google下,然后总结下来...

32660
来自专栏阮一峰的网络日志

在PHP语言中使用JSON

我写过一篇《数据类型和JSON格式》,探讨它的设计思想。今天,我想总结一下PHP语言对它的支持,这是开发互联网应用程序(特别是编写API)必须了解的知识。

14330
来自专栏阮一峰的网络日志

Stack的三种含义

学习编程的时候,经常会看到stack这个词,它的中文名字叫做"栈"。 理解这个概念,对于理解程序的运行至关重要。容易混淆的是,这个词其实有三种含义,适用于不同的...

33540
来自专栏Petrichor的专栏

python: TODO 助记符

TODO 在 python 中作为一种 助记符 (Mnemonics),用来解释 将要做什么 。

17220
来自专栏码云1024

python简明笔记

通过 for 语句我们可以使用 for 循环。Python 里的 for 循环与 C 语言中的不同。这里的 for 循环遍历任何序列(比如列表和字符串)中的每一...

63290
来自专栏Python爬虫与数据挖掘

Python正则表达式初识(八)

继续分享Python正则表达式的基础知识,今天给大家分享的特殊字符是“\w”和“\W”,具体的教程如下。

13050
来自专栏我是攻城师

理解Java8的数据类型和运行时数据区域

Java虚拟机包含对对象的显式支持,对象要么是动态分配的类实例,要么是静态数组,对对象的引用我们可以叫做指针或者引用,一个对象可以有多个引用,对象总是通过引用的...

17230
来自专栏专注 Java 基础分享

虚拟机字节码执行引擎

所谓的「虚拟机字节码执行引擎」其实就是 JVM 根据 Class 文件中给出的字节码指令,基于栈解释器的一种执行机制。通俗点来说,也就是 JVM 解析字节码指令...

26940
来自专栏JavaEdge

Java语法糖1 泛型与类型擦除

39070

扫码关注云+社区

领取腾讯云代金券