1、JAVA中Object对象内存布局JOL

JAVA中Object对象内存布局JOL

  • 前言:
    我们都知道JAVA是面向对象的语言,JAVA中的所有的类都继承自Object;那某一天你在面试的时候,有一个为难你的面试官给你灵魂三问:“Object是什么?能干什么?占用多少内存?” 如果这三个问题都能回答上了那恭喜你,就不用往下看了
  • Objcet内存整体布局初探

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uxrnWPHT-1687526591741)(./img/1.1.JOL.png)]

说明:Object对象 由12Bytes的对象头+对象体组成,由于Object对象没有属性,所以对象体不占空间,那Java Object对象是不是只有12个字节呢;答案是否定了,为了对象占用内存字节数能被8整除,所以要进行字节补齐;12字节无法被8整除,能被8整除,那就只能再补齐4个字节凑成16Bytes;所以正常情况下Object对象占用16Bytes;后续我们会说不正常情况;
其中12字节的对象头中前8字节是markword,后面4字节是生成该对象的类指针Class point;其中m在这里插入图片描述
arkword是什么,在后面回揭晓;

  • 代码验证Object的对象和Persion的对象

    • 验证过程:

      说明:引用jol包,这个包是用来进行对象内存布局打印的;以下是jol包一些常用的方法

      • 计算对象的大小(单位为字节):ClassLayout.parseInstance(obj).instanceSize()
      • 查看对象内部信息: ClassLayout.parseInstance(obj).toPrintable()
      • 查看对象外部信息:包括引用的对象:GraphLayout.parseInstance(obj).toPrintable()
      • 查看对象占用空间总大小:GraphLayout.parseInstance(obj).totalSize()
        后续通过jol包打印Objcet对象内存布局和自己写的Persion类的内存布局,Persion类就加了一个字符串类型的name属性;
      <dependency>
          <groupId>org.openjdk.jol</groupId>
          <artifactId>jol-core</artifactId>
          <version>0.10</version>
      </dependency>
      
      
      public class App 
      {
          public static void main( String[] args )
          {
              System.out.println("Object内部信息");
              Object o=new Object();
              System.out.println(ClassLayout.parseInstance(o).toPrintable());
      
              System.out.println("Persion内部信息");
              Persion p=new Persion();
              System.out.println(ClassLayout.parseInstance(p).toPrintable());
          }
      }
      
    • 验证结果
      JOL core 运行结果
      从图中可以看见正如上面所说Object对象总共占用了16个字节,其中markword 8字节,类指针(Class point)4个字节,由于这markword和class point总共就12个字节,不能被8整除,所以添加了4字节的填充,加一起总共16字节;
      由于Java对象中所有对象都继承自Objcet,所以Persion对象肯定包含Object的12位对象头,但是由于Persion类自身包含了一个字符串属性指向这个属性的指针是4字节(当然对象内存中不会直接存储这个字符串属性本身,而是存储指向字符串实际存储位置的指针),对象头+对象体=16个字节能被8整除,这个时候就无需加入填充字节;所以Persion类生成的对象和Objcet生成的对象本身占用字节数都是16字节(当然这个不等于Object和Persion生成的对象实际占用内存一样,因为persion属性实际还要占用内存)

    也许大家很疑惑,我64位机器怎么类指针只有4个字节(32位),同时Persion字符串类型的指针也只有4字节?别着急,稍后看下面的JVM参数-XX:+UseCompressedOops和 -XX:+UseCompressedClassPointers;

  • 虚拟机参数UseCompressedOops和UseCompressedClassPointers
    带着上面指针怎么只有4字节的疑问,认识一下UseCompressedOops和UseCompressedClassPointers;
    UseCompressedOops:普通对象指正压缩,其中Oop就是"ordinary object pointer";UseCompressedClassPointers配置是否开启类指正压缩;默认JVM开启了普通对象指针压缩和类职称压缩;所以上面类指针和对象属性指针都只有4个字节;这就是上面说的正常情况了;如果非正常(关闭UseCompressedOops和UseCompressedClassPointers)情况Object占用多少内存呢?答案还是16Bytes,关闭普通对象指针压缩和类指针压缩,那64位机器,指针是64位也就是8字节,Object就有8字节的markword加上8字节的类指针还是16字节,和开启指针压缩的唯一区别就是这个时候类没有字节补齐;当然非正常情况下(关闭指针压缩)Persion类对象就是16字节头+8字节的Persion属性,总共24字节,由于能被8整除所以没有字节对齐填充

java -XX:+PrintCommandLineFlags  --version
-XX:ConcGCThreads=2 
-XX:G1ConcRefinementThreads=8 
-XX:GCDrainStackTargetSize=64 
-XX:InitialHeapSize=534566336 
-XX:MarkStackSize=4194304 
-XX:MaxHeapSize=8553061376 
-XX:MinHeapSize=6815736 
-XX:+PrintCommandLineFlags 
-XX:ReservedCodeCacheSize=251658240 
-XX:+SegmentedCodeCache 
# 类指针压缩
-XX:+UseCompressedClassPointers 
# 普通对象指针压缩,oops: ordinary object pointer
-XX:+UseCompressedOops 
-XX:+UseG1GC 
-XX:-UseLargePagesIndividualAllocation 
java 17.0.4.1 2022-08-18 LTS
Java(TM) SE Runtime Environment (build 17.0.4.1+1-LTS-2)
Java HotSpot(TM) 64-Bit Server VM (build 17.0.4.1+1-LTS-2, mixed mode, sharing)
  • Mark Word说明
    JAVA JOL Mark Word说明
    以下是简单说明,后续文章结合synchronized进行详细说明
    • 锁标志:2位,锁状态的标记位,
    • 偏向锁标志:1位对象是否存在偏向锁标记。锁标志与偏向锁标记共同表示锁对象处于什么锁状态。
    • 分代年龄:4位,表示JAVA对象的年龄,在GC中,当survivor区中对象复制一次,年龄加1,如果到15之后会移动到老年代,并发GC的年龄阈值为6.
    • identity_hashcode:31位,调用方法 System.identityHashCode()计算,并会将结果写到该对象头中。当对象加锁后(偏向、轻量级、重量级),MarkWord的字节没有足够的空间保存hashCode,因此该值会移动到线程 Monitor中。
    • 当前线程指针Thread:54位,持有偏向锁的线程ID(此处的线程id是操作系统层面的线程唯一Id,与java中的线程id是不一致的,了解即可)。
    • epoch:2位,偏向锁的时间戳。
    • 指向线程中Lock Record: ptr_to_lock_record,62位,轻量级锁状态下,指向栈中锁记录的指针。
    • 指向互斥量的指针:ptr_to_heavyweight_monitor,62位,重量级锁状态下,指向对象监视器 Monitor的指针。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值