java对象内存布局

咱们知道在Java中基本数据类型的大小,例如int类型占4个字节、long类型占8个字节,那么Integer对象和Long对象会占用多少内存呢?本文介绍一下Java对象在堆中的内存结构以及对象大小的计算。数组

对象的内存布局

一个Java对象在内存中包括对象头、实例数据和补齐填充3个部分:布局

 

对象头

  • Mark Word:包含一系列的标记位,好比轻量级锁的标记位,偏向锁标记位等等。在32位系统占4字节,在64位系统中占8字节;
  • Class Pointer:用来指向对象对应的Class对象(其对应的元数据对象)的内存地址。在32位系统占4字节,在64位系统中占8字节;
  • Length:若是是数组对象,还有一个保存数组长度的空间,占4个字节;

对象实际数据

对象实际数据包括了对象的全部成员变量,其大小由各个成员变量的大小决定,好比:byte和boolean是1个字节,short和char是2个字节,int和float是4个字节,long和double是8个字节,reference是4个字节(64位系统中是8个字节)。优化

Primitive Type Memory Required(bytes)
boolean 1
byte 1
short 2
char 2
int 4
float 4
long 8
double 8

对于reference类型来讲,在32位系统上占用4bytes, 在64位系统上占用8bytes。ui

对齐填充

Java对象占用空间是8字节对齐的,即全部Java对象占用bytes数必须是8的倍数。例如,一个包含两个属性的对象:int和byte,这个对象须要占用8+4+1=13个字节,这时就须要加上大小为3字节的padding进行8字节对齐,最终占用大小为16个字节。spa

注意:以上对64位操做系统的描述是未开启指针压缩的状况,关于指针压缩会在下文中介绍。操作系统

对象头占用空间大小

这里说明一下32位系统和64位系统中对象所占用内存空间的大小:3d

  • 在32位系统下,存放Class Pointer的空间大小是4字节,MarkWord是4字节,对象头为8字节;
  • 在64位系统下,存放Class Pointer的空间大小是8字节,MarkWord是8字节,对象头为16字节;
  • 64位开启指针压缩的状况下,存放Class Pointer的空间大小是4字节,MarkWord是8字节,对象头为12字节;
  • 若是是数组对象,对象头的大小为:数组对象头8字节+数组长度4字节+对齐4字节=16字节。其中对象引用占4字节(未开启指针压缩的64位为8字节),数组MarkWord为4字节(64位未开启指针压缩的为8字节);
  • 静态属性不算在对象大小内。

指针压缩

从上文的分析中能够看到,64位JVM消耗的内存会比32位的要多大约1.5倍,这是由于对象指针在64位JVM下有更宽的寻址。对于那些将要从32位平台移植到64位的应用来讲,平白无辜多了1/2的内存占用,这是开发者不肯意看到的。指针

从JDK 1.6 update14开始,64位的JVM正式支持了 -XX:+UseCompressedOops 这个能够压缩指针,起到节约内存占用的新参数。code

什么是OOP?

OOP的全称为:Ordinary Object Pointer,就是普通对象指针。启用CompressOops后,会压缩的对象:对象

  • 每一个Class的属性指针(静态成员变量);
  • 每一个对象的属性指针;
  • 普通对象数组的每一个元素指针。

固然,压缩也不是全部的指针都会压缩,对一些特殊类型的指针,JVM是不会优化的,例如指向PermGen的Class对象指针、本地变量、堆栈元素、入参、返回值和NULL指针不会被压缩。

启用指针压缩

在Java程序启动时增长JVM参数:-XX:+UseCompressedOops来启用。

注意:32位HotSpot VM是不支持UseCompressedOops参数的,只有64位HotSpot VM才支持。

本文中使用的是JDK 1.8,默认该参数就是开启的。

相关文章
相关标签/搜索