Java对象内存布局和内存大小计算

1.对象的内存布局

    在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)和 对齐填充(Padding)下图是普通对象实例对象结构 与 数组对象实例的数据结构:

(1)Java对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。也就是 JAVA对象 = 对象头 + 实例数据 + 对象填充

(2)对象头(Header)包含三部分信息:markword、klass对象指针、length数组长度。

(1)对象头(Header)

    HotSpot虚拟机的对象头包括三部分信息:markword + _klass对象指针 + 数组长度需要注意的是32位vm 和 64位vm对应每个部分占用的大小是不一样的。

  • 1)markword
    用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32bit和64bit,官方称它为“MarkWord”。

  • 2)_klass
    class对象指针。即对象指向它的类元数据(metadata)的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。如果未启用指针压缩这部分数据的长度在32位和64位的虚拟机中分别为32bit和64bit,64位vm开启compressed后_klass数据长度是64bit。

#1.JVM支持klass指针压缩,虚拟机是64位系统时默认开始了指针(compressed)压缩。
(1)jvm配置参数:UseCompressedOops来开启或禁止指针压缩(compressed--压缩、oop--对象指针)。
(2)启用指针压缩:-XX:+UseCompressedOops,禁止指针压缩:-XX:-UseCompressedOops

#2.在64位虚拟机默认开启压缩指针的环境下_klass占用32bits空间,没开启指针压缩时_klass占用64bits。
  • 3)数组长度(只有数组对象才有)

如果对象是一个数组, 那在对象头中还必须有一块数据用于记录数组长度。这部分数据在的长度在32位和64位的虚拟机中都是32bit。

 Java对象头里的Mark Word里默认存储对象的HashCode、GC分代年龄、偏向锁状态和锁标志位。32位JVM的Mark Word的默认存储结构(无锁状态)如表:

 在运行期间,Mark Word里存储的数据会随着锁标志位的变化而变化。Mark Word每种锁标志对应的存储的数据如下四种:

(2)实例数据

    实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。无论是从父类继承下来的,还是在子类中定义的,都需要记录起来。原生类型(primitive type)的内存占用如下:

数据类型 占用字节数 备注
boolean 1  
byte 1  
short 2  
char 2  
int 4  
float 4  
long 8  
double 8  
reference 4/8 引用类型在32位系统上每个占用4bytes, 在64位系统上每个占用8bytes。

(3)对齐填充

     第三部分对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。hotspot vm 的自动内存管理系统要求对象起始地址比必须位 8 字节的整数倍,即对象的大小必须是 8 字节的整数倍。当对象头 + 实例数据大小不足8字节的倍数时,会进行自动填充到8字节的倍数大小。

#1.无论是64位vm,还是32位vm,对齐填充位都是满足8字节的倍数。

#2.new object()到底占多少个字节? 
  由于new object()没有实例数据和数组长度,只有对象头占内存空间。从上面Header存储信息可以看出在32位VM、64位VM中总共有3种对象头模型。
	(1)在32位VM中:32bit的markword + 32bit的klass = 8字节。
	(2)64位VM中,且不开启指针压缩:64bit的markword + 64bit的klass = 16字节
	(3)64位JVM中,且开启指针压缩: 64bit的markword + 32bit的klass + 4字节的padding = 16字节

2.对象内存大小计算

   OpenJDK提供了JOL包,可以帮我们计算出某个对象在运行时内存分布、占用内存大小,用它能找出一个对象究竟败了多少内存,是一个非常好的工具。

(1)jol的maven依赖

<!-- openjdk的jol工具查看对象内存分布 -->
<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.10</version>
</dependency>

(2)对象占用内存分析

   接下来我们用两个例子来分析一个空对象 和 有实例数据的对象在运行时时期,占用内存大小。
1)空对象分析

//先声明一个空对象类
public class MyObject {
}

//测试方法
public static void main(String[] args) {
	Layouter l;
	//32位vm对象分布
	l = new HotSpotLayouter(new X86_32_DataModel());
	System.out.println("***** " + l);
	System.out.println(ClassLayout.parseClass(MyObject.class, l).toPrintable());
	System.out.println("==============================================");
	
	//64位vm对象分布,未启动指针压缩
	l = new HotSpotLayouter(new X86_64_DataModel());
	System.out.println("***** " + l);
	System.out.println(ClassLayout.parseClass(MyObject.class, l).toPrintable());
	System.out.println("==============================================");
	
	//64位vm对象分布,启动指针压缩
	l = new HotSpotLayouter(new X86_64_COOPS_DataModel());
	System.out.println("***** " + l);
	System.out.println(ClassLayout.parseClass(MyObject.class, l).toPrintable());
}

//输出对象内存分布信息
//(1)32位vm对象分布,MyObject对象大小:8字节的header(4字节markword、4字节klass指针)
***** VM Layout Simulation (X32 model, 8-byte aligned, compact fields, field allocation style: 1)
lock.MyObject object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     8        (object header)                           N/A
Instance size: 8 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
==============================================

//(2)64位vm未启动指针压缩,MyObject对象大小: 16字节的header(8字节markword、8字节klass指针)
***** VM Layout Simulation (X64 model, 8-byte aligned, compact fields, field allocation style: 1)
lock.MyObject object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0    16        (object header)                           N/A
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
==============================================

//(3)64位vm启动指针压缩,MyObject对象大小: 12字节的header(8字节markword、4字节klass指针) + 4字节的对齐填充
***** VM Layout Simulation (X64 model (compressed oops), 8-byte aligned, compact fields, field allocation style: 1)
lock.MyObject object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0    12        (object header)                           N/A
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

2)非空对象,有实例数据分析

//先声明一个有成员变量的非空对象类
public class MyObject {
    int i;
    long j;
    MyObject object;
}

//测试方法
public static void main(String[] args) {
	Layouter l;
	//32位vm对象分布
	l = new HotSpotLayouter(new X86_32_DataModel());
	System.out.println("***** " + l);
	System.out.println(ClassLayout.parseClass(MyObject.class, l).toPrintable());
	System.out.println("==============================================");
	
	//64位vm对象分布,未启动指针压缩
	l = new HotSpotLayouter(new X86_64_DataModel());
	System.out.println("***** " + l);
	System.out.println(ClassLayout.parseClass(MyObject.class, l).toPrintable());
	System.out.println("==============================================");
	
	//64位vm对象分布,启动指针压缩
	l = new HotSpotLayouter(new X86_64_COOPS_DataModel());
	System.out.println("***** " + l);
	System.out.println(ClassLayout.parseClass(MyObject.class, l).toPrintable());
}

//输出对象内存分布信息
//(1)32位vm对象分布,MyObject对象大小:8字节的header(4字节markword、4字节klass指针) + 4字节的int变量i + 8字节的long变量j + 4字节的引用变量object
***** VM Layout Simulation (X32 model, 8-byte aligned, compact fields, field allocation style: 1)
lock.MyObject object internals:
 OFFSET  SIZE            TYPE DESCRIPTION                               VALUE
      0     8                 (object header)                           N/A
      8     8            long MyObject.j                                N/A
     16     4             int MyObject.i                                N/A
     20     4   lock.MyObject MyObject.object                           N/A
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
==============================================

//(2)64位vm未启动指针压缩,MyObject对象大小: 16字节的header(8字节markword、8字节klass指针) + 4字节的int变量i + 8字节的long变量j + 8字节的引用变量object + 4字节的对齐填充
***** VM Layout Simulation (X64 model, 8-byte aligned, compact fields, field allocation style: 1)
lock.MyObject object internals:
 OFFSET  SIZE            TYPE DESCRIPTION                               VALUE
      0    16                 (object header)                           N/A
     16     8            long MyObject.j                                N/A
     24     4             int MyObject.i                                N/A
     28     4                 (alignment/padding gap)                  
     32     8   lock.MyObject MyObject.object                           N/A
Instance size: 40 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
==============================================

//(3)64位vm未启动指针压缩,MyObject对象大小: 12字节的header(8字节markword、4字节klass指针) + 4字节的int变量i + 8字节的long变量j + 4字节的引用变量object + 4字节的对齐填充
***** VM Layout Simulation (X64 model (compressed oops), 8-byte aligned, compact fields, field allocation style: 1)
lock.MyObject object internals:
 OFFSET  SIZE            TYPE DESCRIPTION                               VALUE
      0    12                 (object header)                           N/A
     12     4             int MyObject.i                                N/A
     16     8            long MyObject.j                                N/A
     24     4   lock.MyObject MyObject.object                           N/A
     28     4                 (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

猜你喜欢

转载自blog.csdn.net/Seky_fei/article/details/106040628