java对象模型其实就是JVM中对象的内存布局。一个对象本身内在结构的描述信息以字节码的方式存储在方法区中(参见java内存区域),说白了就是class文件。那么如何获取到对象的class信息呢?虚拟机使用对象头部的一个指针指向 Class 区域,找到对象的 Class 描述。在虚拟机中,对象在内存中的存储布局分为 3 块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding):

  一、对象头

  包括两部分(非数组对象)信息:

  第一部分用于存储对象自身的运行时数据,如哈希码(HashCode)、GC 分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳、对象分代年龄,这部分信息称为“Mark Word”。Mark Word 被设计成一个非固定的数据结构以便在极小的空间内存储尽量多的信息,它会根据自己的状态复用自己的存储空间;

  第二部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例;

  如果是数组对象,那么还有第三部分:一块用于记录数组长度的数据。虚拟机可以通过普通Java对象的元数据信息确定对象的大小,但是从数组的元数据信息却无法确定数组的大小。

    

  对象头的数据的长度在 32 位和 64 位的虚拟机(未开启压缩指针)中分别为32bit 和 64bit。在 32 位的 HotSpot 虚拟机中,如果对象处于未被锁定的状态下,那么 Mark Word 的 32bit 空间中的 25bit 用于存储对象哈希码,4bit 用于存储对象分代年龄,2bit 用于存储锁标志位,1bit 固定为 0,如下表所示:

  在 32 位系统下,存放 Class 指针的空间大小是 4 字节,Mark Word 空间大小也是4字节,因此头部就是 8 字节,如果是数组就需要再加 4 字节表示数组的长度,如下表所示:

  在 64 位系统及 64 位 JVM 下,开启指针压缩,那么头部存放 Class 指针的空间大小还是4字节,而 Mark Word 区域会变大,变成 8 字节,也就是头部最少为 12 字节,如下表所示:

  开启指针压缩使用算法开销带来内存节约,Java 对象都是以 8 字节对齐的,也就是以 8 字节为内存访问的基本单元,那么在地理处理上,就有 3 个位是空闲的,这 3 个位可以用来虚拟,利用 32 位的地址指针原本最多只能寻址 4GB,但是加上 3 个位的 8 种内部运算,就可以变化出 32GB 的寻址。

  代码清单2-2为HotSpot虚拟机markOop.cpp中的代码(注释)片段,它描述了32bit下Mark Word的存储状态:

  

  二、实例数据

  实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。

  这部分的存储顺序会受到虚拟机分配策略参数(FieldsAllocationStyle)和字段在 Java 源码中定义顺序的影响。

  HotSpot虚拟机默认的分配策略为longs/doubles、ints、shorts/chars、bytes/booleans、oops(Ordinary Object Pointers),从分配策略中可以看出,相同宽度的字段总是被分配到一起。在满足这个前提条件的情况下,在父类中定义的变量会出现在子类之前。如果 CompactFields参数值为true(默认为true),那子类之中较窄的变量也可能会插入到父类变量的空隙之中。

  三、对齐信息

  对齐填充不是必然存在的,没有特别的含义,它仅起到占位符的作用。

  由于 HotSpot VM 的自动内存管理系统要求对象起始地址必须是 8 字节的整数倍,也就是说对象的大小必须是 8 字节的整数倍。对象头部分是 8 字节的倍数,所以当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。

  四、对象的大小

  class的大小通常是KB级别,随便找个类文件一看便知:

$ ll
total
-rw-r--r-- wulf 11月 : CycleTypes.class
-rw-r--r-- wulf 11月 : User.class

  从上面可以看到,两个class,一个是5172字节,一个是1245字节。那么对象一般是多大呢?32 位系统下,当使用 new Object() 时,JVM 将会分配 8(Mark Word+类型指针) 字节的空间,128 个 Object 对象将占用 1KB 的空间。
如果是 new Integer(),那么对象里还有一个 int 值,其占用 4 字节,这个对象也就是 8+4=12 字节,对齐后,该对象就是 16 字节。

  如果对象存在多个属性字段,它的内部属性是怎么排布的?

Class A {
int i;
byte b;
String str;
}

  其中对象头部占用 ‘Mark Word’4字节 + ‘类型指针’4字节 = 8 字节;int 32 位长,占用 4 字节;byte 8 位长,占用 1 字节;String 只有引用,占用 4 字节;那么对象 A 一共占用了 8+4+1+4=17 字节,按照 8 字节对齐原则,对象大小也就是 24 字节。这个计算看起来是没有问题的,对象的大小也确实是 24 字节,但是对齐(padding)的位置并不对:在 HotSpot VM 中,对象排布时,间隙是在 4 字节基础上的(在 32 位和 64 位压缩模式下),上述例子中,int 后面的 byte,空隙只剩下 3 字节,接下来的 String 对象引用需要 4 字节来存放,因此 byte 和对象引用之间就会有 3 字节对齐,对象引用排布后,最后会有 4 字节对齐,因此结果上依然是 7 字节对齐。此时对象的结构示意图,如下图所示:

java对象模型的更多相关文章

  1. 【JVM】JVM内存结构 VS Java内存模型 VS Java对象模型

    原文:JVM内存结构 VS Java内存模型 VS Java对象模型 Java作为一种面向对象的,跨平台语言,其对象.内存等一直是比较难的知识点.而且很多概念的名称看起来又那么相似,很多人会傻傻分不清 ...

  2. 【转】JVM内存结构 VS Java内存模型 VS Java对象模型

    JVM内存结构 我们都知道,Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途. 其中有些区域随着虚拟机进程的启动而 ...

  3. java内存结构JVM——java内存模型JMM——java对象模型JOM

    JVM内存结构 Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途.其中有些区域随着虚拟机进程的启动而存在,而有些区 ...

  4. JVM(八):Java 对象模型

    JVM(八):Java 对象模型 本文将学习对象是如何创建的,对象的内存布局,以及如何定位访问一个对象. 对象创建 当虚拟机碰到一个new指令时,首先检查指令参数能否在常量池中定位一个类的符号引用,并 ...

  5. JVM内存结构 VS Java内存模型 VS Java对象模型

    前面几篇文章中, 系统的学习了下JVM内存结构.Java内存模型.Java对象模型, 但是发现自己还是对这三者的概念和区别比较模糊, 傻傻分不清楚.所以就有了这篇文章, 本文主要是对这三个技术点再做一 ...

  6. 区分 JVM 内存结构、 Java 内存模型 以及 Java 对象模型 三个概念

    本文由 简悦 SimpRead 转码, 原文地址 https://www.toutiao.com/i6732361325244056072/ 作者:Hollis 来源:公众号Hollis Java 作 ...

  7. Java内存模型、JVM内存结构和Java对象模型

    JVM内存结构 我们都知道,Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途.其中有些区域随着虚拟机进程的启动而存 ...

  8. JVM内存结构、Java内存模型和Java对象模型

    Java作为一种面向对象的,跨平台语言,其对象.内存等一直是比较难的知识点.而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚.比如本文要讨论的JVM内存结构.Java内存模型和Java对象模型 ...

  9. [转帖]JVM内存结构 VS Java内存模型 VS Java对象模型

    JVM内存结构 VS Java内存模型 VS Java对象模型 https://www.hollischuang.com/archives/2509 Java作为一种面向对象的,跨平台语言,其对象.内 ...

随机推荐

  1. TrueCrypt简介及TrueCrypt 7.1a Source.zip源码在VS2008下的编译过程

    转载:http://blog.csdn.net/cncrypt/article/details/51565493 转载:http://www.cnblogs.com/shenjieblog/p/521 ...

  2. InstallShield 2015 LimitedEdition VS2012 运行bat文件

    转载:http://www.cnblogs.com/fengwenit/p/4271150.html  运行bat文件 网上很多介绍如何运行bat的方法,但我这个是limted 版本,不适用. 1. ...

  3. 安装tensorflow报ImportError: libcublas.so.9.0: cannot open shared object file的解决方法【转】

    本文转载自:https://blog.csdn.net/qq_37274615/article/details/81099738 转载自:https://blog.csdn.net/qysh123/a ...

  4. nginx限制蜘蛛的频繁抓取

    蜘蛛抓取量骤增,导致服务器负载很高.最终用nginx的ngx_http_limit_req_module模块限制了百度蜘蛛的抓取频率.每分钟允许百度蜘蛛抓取200次,多余的抓取请求返回503. ngi ...

  5. github上fork别人的代码之后,如何保持和原作者同步的更新

    1.从自己fork之后的版本库clone $  git clone -o chucklu https://github.com/chucklu/Hearthstone-Deck-Tracker.git ...

  6. G_M_网络流A_网络吞吐量

    调了两天的代码,到最后绝望地把I64d改成lld就过了,我真的是醉了. 网络吞吐量 题面:给出一张(n个点,m条边)带权(点权边权均有)无向图,点权为每个点每秒可以接受发送的最大值,边权为花费,保证数 ...

  7. __autoload自动加载类

    在使用PHP的OO模式开发系统时,通常大家习惯上将每个类的实现都存放在一个单独的文件里,这样会很容易实现对类进行复用,同时将来维护时也很便利.这也是OO设计的基本思想之一.在PHP5之前,如果需要使用 ...

  8. QWebEngineView_简单例子_01

    工程名 : WebEngine01 1.WebEngine01.pro #------------------------------------------------- # # Project c ...

  9. 深入浅出 Hadoop YARN

    一. Hadoop Yarn 是什么 在古老的 Hadoop1.0 中,MapReduce 的 JobTracker 负责了太多的工作,包括资源调度,管理众多的 TaskTracker 等工作.这自然 ...

  10. kue

    尝试着看英文的文档,你发现他其实并不难. https://www.npmjs.com/package/kue