Java 对象占用内存大小——转自java404

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 对象在堆中的占用空间大小

代码示例一

  1. public class StrObj1 {

  2.    private String a;

  3. }

  4. public class StrObj2 {

  5.    private String a;

  6.    private String b;

  7. }

  8. public class StrObj3 {

  9.    private String a;

  10.    private String b;

  11.    private String c;

  12. }

  13. public class StrObj4 {

  14.    private String a;

  15.    private String b;

  16.    private String c;

  17.    private String d;

  18. }

  19. public class NumObj {

  20.    private int a;

  21.    private int b;

  22.    private int c;

  23.    private int d;

  24. }

  25. public class Obj {

  26.    public static void main(String[] args) {

  27.        Obj obj = new Obj();

  28.        StrObj1 s1 = new StrObj1();

  29.        StrObj2 s2 = new StrObj2();

  30.        StrObj3 s3 = new StrObj3();

  31.        StrObj4 s4 = new StrObj4();

  32.        Obj[] arrObj = new Obj[10];

  33.        NumObj num = new NumObj();

  34.                //System.gc()  会出发 FullGC。

  35.        System.gc();

  36.    }

  37. }

运行程序

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

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

代码示例 二

  1. public class BooleanObj1 {

  2.    boolean a;

  3. }

  4.  

  5. ......

  6.  

  7. public class BooleanObj8 {

  8.    boolean a;

  9.    boolean b;

  10.    boolean c;

  11.    boolean d;

  12.    boolean e;

  13.    boolean f;

  14.    boolean g;

  15.    boolean h;

  16. }

  17. public class BooleanObj9 {

  18.    boolean a;

  19.    boolean b;

  20.    boolean c;

  21.    boolean d;

  22.    boolean e;

  23.    boolean f;

  24.    boolean g;

  25.    boolean h;

  26.    boolean i;

  27. }

以指针非压缩方式执行,然后分析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

 

 


 

喜欢本文的朋友们,欢迎长按下图关注订阅号 java404,收听更多精彩的内容

 
posted @ 2022-03-05 21:45  好Wu赖  阅读(249)  评论(0编辑  收藏  举报