zoukankan      html  css  js  c++  java
  • 对象在内存中的内存布局是什么样的?

    一个Java对象的存储结构。在Hotspot虚拟机中,对象在内存中的存储布局分为 3 块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)

    Java 对象实例


    Hotspt 采用了 OOP-Klass 模型。 它是描述 java 对象实例的模型,可分为两部分:

    OOP (Ordinary Object Pointer)指的是普通对象指针,它包含 MarkWord 和Klass 指针。MarkWord 用于存储当前对象运行时的一些状态数据;Klass 指针则指向 Klass,用来告诉当前指针指向的对象是什么类型,即对象是使用哪个类创建出来的
    之所以采用这种一分为二的对象模型,是因为 hotspot jvm 的设计者不想让每个对象中都包含一个 virtual table (虚函数表), 所以把对象模型拆成 klass 和 oop,其中 oop 不包含任何虚函数,而 klass 含有虚函数表,可以进行method dispatch


    - 对象头
    HotSpot虚拟机的对象头包括两部分信息:

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

    _klass:klassOop
    对象头的另外一部分是klass类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例

    length
    如果是数组对象的话,对象头还有一块表示数组长度的数据,大小是32bit,4个字节

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

    - 对齐填充
    第三部分对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数(1倍或者2倍),因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。

    简单可以概括如下

    知道了这4个部分之后,我们来验证一下底层。借助于第三方包 JOL = Java Object Layout java内存布局去看看。很简单的几行代码就可以看到内存布局的样式:

    <dependency>
         <groupId>org.openjdk.jol</groupId>
         <artifactId>jol-core</artifactId>
         <version>0.9</version>
    </dependency>
    

     

    public class JOLSampleDataModels {
     
        private static Object o;
     
        public static void main(String[] args) {
            o = new Object();
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
            System.out.println("================== 加载锁之后 ==================");
            synchronized (o) {
                System.out.println(ClassLayout.parseInstance(o).toPrintable());
            }
        }
    }
    

      

    从输出结果看:

    对象头包含了12个字节分为3行,其中前2行其实就是markword,第三行就是klass指针。值得注意的是在加锁前后输出从001变成了000。Markword用处:8字节(64bit)的头记录一些信息,锁就是修改了markword的内容8字节(64bit)的头记录一些信息,锁就是修改了markword的内容字节(64bit)的头记录一些信息。从001无锁状态,变成了00轻量级锁状态。

    • New出一个object对象,占用16个字节。对象头占用12字节,由于Object中没有额外的变量,所以instance = 0,考虑要对象内存大小要被8字节整除,那么padding=4,最后new Object() 内存大小为16字节。

    拓展

    什么样的对象会进入老年代?很多场景例如对象太大了可以直接进入,但是这里想探讨的是为什么从Young GC的对象最多经历15次Young GC还存活就会进入Old区(年龄是可以调的,默认是15)。上图中hotspots的markword的图中,用了4个bit去表示分代年龄,那么能表示的最大范围就是0-15。所以这也就是为什么设置新生代的年龄不能超过15,工作中可以通过-XX:MaxTenuringThreshold去调整,但是一般我们不会动。

    【原文地址】:原文跳转
    专注于系统架构、高可用、高性能、高并发类技术分享

  • 相关阅读:
    008. redis 主从复制原理、断点续传、无磁盘化复制、过期 key 处理
    007.redis replication 以及 master 持久化对主从架构的安全意义
    006. redis 如何通过读写分离来承载读请求 QPS 超过 10 万 +?
    005.在项目中部署 redis 企业级数据备份方案以及各种踩坑的数据恢复容灾演练
    人月神话---向进度落后的项目中增加人手,只会使进度更加落后
    人月神话---空泛的估算
    人月神话---不为系统测试安排足够的时间简直就是一场灾难
    人月神话---成本的确随开发产品的人数和时间的不同,有着很大的变化,进度却不是如此
    springmvc其他类获取request记得web.xml
    gson转换问题
  • 原文地址:https://www.cnblogs.com/ibytecoding/p/15061166.html
Copyright © 2011-2022 走看看