java对象内存_聊聊java对象内存布局

我们知道在java的世界里面对象无处不在,那你又知不知道对象在java里面具体是如何存在的呢,比如对象由哪些部分组成,每个部分具体组成又是什么。下面我们来走进java的对象世界,了解java对象的内存布局吧。

java数据类型的分类

java里面数据类型主要分为原生类型,类,接口,数组这几种。原生类型包括了int、long、double、char、byte等原生类型。原生类型对应的包装类型如Integer、Long、Double这些在java里面归类到类(class)里面,这里为了描述方便把接口(interface)也归类到类(class)里面。所以总的来说java的数据类型主要归为三类原生类型,类(class),数组。其中只有类和数组在java虚拟机里面是对象的形式的创建的,所以我们说的对象通常就是指类和数组的实例。

对象的组成

根据java虚拟机规范里面的描述:java对象分为三部分:对象头(Object Header), 实例数据(instance data),对齐填充(padding)。如图:

下面我们以对象(Ojbect)为例分析每一部分组成。数组与对象类似,只是对象头部分多了数组长度Length的存储长度为4字节。

对象头(Object Header):

从图片上得知对象头分为两部分:Mark Word 与 Class Pointer(类型指针)。

Mark Word存储了对象的hashCode、GC信息、锁信息三部分,Class Pointer存储了指向类对象信息的指针。在32位JVM上对象头占用的大小是8字节,64位JVM则是16字节,两种类型的Mark Word 和 Class Pointer各占一半空间大小。

在64位JVM上有一个压缩指针选项-XX:+UseCompressedOops,默认是开启的。开启之后Class Pointer部分就会压缩为4字节,此时对象头大小就会缩小到12字节。

下面是用一张图展示 32位JVM上对象头的内存分布,方便理解。

实例数据(instance data):

有一种错觉就是实例数据里面通常只存了数据本身,但实际上这部分JVM也做了对齐填充,这样做的目的是为了内存对齐,为了实现这个效果JVM会执行一个字段重排列的操作。

字段重排列: 故名思义就是JVM在分配内存时不一定是完全按照类定义的字段顺序去分配,而是根据JVM选项-XX:FieldsAllocationStyle(默认是1)来进行排序。对于所有的

-XX:FieldsAllocationStyle配置选项来说都会遵守以下两个原则:

1、如果一个字段的大小为S字节,则对象开始的位置到该字段的位置的偏移量一定满足:

该字段的位置 - 对象开始位置 = mS (m >=1) 即是S的m倍。

在64位JVM开启压缩指针的基础上举个例子:

对象的分配第一个字段是个long 类型,这时对 象头的大小为12个字节,long的大小8个字节。14不能整除8,这时JVM会填充4个字节。让字段的位置从16开始,这样压缩节省出来的4字节空间又还回去了。。。。

2、子类继承父类字段的偏移量一定和父类是一致的。在具体的64位JVM实现中对还会对比子类的实例数据进行以下对齐:如果开启了压缩指针则子类第一个字段的偏移量是4N,关闭压缩指针之后是8N。

下面通过JOT 工具来验证上面的结论。JOT工具介绍

引入maven依赖:

org.openjdk.jol

jol-core

0.9

运行下面代码,运行环境:64位JVM开启了压缩指针。

import org.openjdk.jol.info.ClassLayout;

import org.openjdk.jol.vm.VM;

/*** java 对象内存分布*/

class A{

long i;

}

public class MemoryLayoutTest {

public static void main(String[] args){

System.out.println(VM.current().details());

System.out.println(ClassLayout.parseClass(A.class).toPrintable());

}

}

得到结果:

memory.A object internals:

OFFSET SIZE TYPE DESCRIPTION VALUE

0 12 (object header) N/A

12 4 (alignment/padding gap)

16 8 long A.i N/A

Instance size: 24 bytes

Space losses: 4 bytes internal + 0 bytes external = 4 bytes total

12 4 (alignment/padding gap)

这一行就表示额外填充了4个字节,字段i的偏移量16满足"mS",原则1得证。

整个对象将占用24个字节的大小。

原则2验证:

class A{

long i;

}

class B extends A{

int j;

}

public class MemoryLayoutTest {

public static void main(String[] args){

System.out.println(VM.current().details());

System.out.println(ClassLayout.parseClass(B.class).toPrintable());

}

}

运行结果:

memory.B object internals:

OFFSET SIZE TYPE DESCRIPTION VALUE

0 12 (object header) N/A

12 4 (alignment/padding gap)

16 8 long A.i N/A

24 4 int B.j N/A

28 4 (loss due to the next object alignment)

Instance size: 32 bytes

Space losses: 4 bytes internal + 4 bytes external = 8 bytes total

看到子类B中字段i的偏移量上面父类A中i的偏移量是一致的,都在16位置。然后子类B的第一个字段j的偏移量正好满足"4N"

下面关闭压缩指针-XX:-UseCompressedOops,然后把父类A和子类B的字段类型修改一下:

class A{

int i;

}

class B extends A{

long j;

}

同样运行之前的代码:

memory.B object internals:

OFFSET SIZE TYPE DESCRIPTION VALUE

0 16 (object header) N/A

16 4 int A.i N/A

20 4 (alignment/padding gap)

24 8 long B.j N/A

Instance size: 32 bytes

Space losses: 4 bytes internal + 0 bytes external = 4 bytes total

我们看到子类B的第一个字段j的偏移量被填充到24,关闭压缩指针之后符合我们的"8N"。

对齐填充:

这里的对齐填充专指对象末尾的填充,如果对象填充完实例数据后的大小不满足"8N",则填充到8N,其实在上面运行结果中就已经有提示了。

memory.B object internals:

OFFSET SIZE TYPE DESCRIPTION VALUE

0 12 (object header) N/A

12 4 (alignment/padding gap)

16 8 long A.i N/A

24 4 int B.j N/A

28 4 (loss due to the next object alignment)

Instance size: 32 bytes

Space losses: 4 bytes internal + 4 bytes external = 8 bytes total

28 4 (loss due to the next object alignment) 这一行表示了在最后JVM填充了4字节让对象的大小由28变成了32,使对象大小满足"8N"。

好了关于java对象的布局就暂时介绍到这里了,在借助工具情况下大家是不是觉得java的内存布局其实也是很好理解呢。

最后简单总结一下:

java对象由三部分组成:对象头,实例数据,对齐填充。

对象头包括Mark Word和 Class Pointer。Mark Word包括对象hashCode,GC信息和锁信息。在32位JVM下对象头大小为8字节。64位16字节,开启压缩指针后为12字节,压缩的是Class Pointer。

实例数据也会有对齐填充。

对象大小一定满足8N

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值