• JVM-JVM中对象的结构


    对象内存布局

    在这里插入图片描述

    对象里的三个区:

    1. 对象头(Header):Java对象头占8byte。如果是数组则占12byte。因为JVM里数组size需要使用4byte存储。
      标记字段MarkWord:
      用于存储对象自身的运行时数据,它是synchronized实现轻量级锁和偏向锁的关键。
      默认存储:对象HashCode、GC分代年龄、锁状态等等信息。
      为了节省空间,也会随着锁标志位的变化,存储数据发生变化。
      标记字段的结构:
      在这里插入图片描述
      类型指针KlassPoint:
      是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例
      开启指针压缩存储空间4byte,不开启8byte。
      JDK1.6+默认开启
      数组长度 如果对象是数组,则记录数组长度,占4个byte,如果对象不是数组则不存在。
      对齐填 保证数组的大小永远是8byte的整数倍。

    2. 实例数据(Instance Data):生成对象的时候,对象的非静态成员变量也会存入堆空间

    3. 对齐填充(Padding):JVM内对象都采用8byte对齐,不够8byte的会自动补齐。

    案例1:

    <dependency>
    	<groupId>org.openjdk.jolgroupId>
    	<artifactId>jol-coreartifactId>
    	<version>0.9version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
     Object o = new Object();
            System.out.println("new Object:" +
                    ClassLayout.parseInstance(o).toPrintable());
    
    • 1
    • 2
    • 3

    在这里插入图片描述
    注:首先对象头是包含MarkWord和类型指针这两部分信息的;
    开启指针压缩的情况下,存放Class指针的空间大小是4字节,MarkWord是8字节,对象头为12字节;
    新建Object对象,会在内存占用16个字节,其中Header占12个(MarkWord占8个+KlassPoint占4个),没有实例数据,补充对齐4个。
    结论:对象大小 = 对象头12 + 实例数据0 + 对齐填充4 = 16 bytes
    在这里插入图片描述
    案例2:

    public class TT {
        public static void main(String[] args) {
            Hero a = new Hero();
            System.out.println("new A:" +
                    ClassLayout.parseInstance(a).
                            toPrintable());
            Hero b = new Hero(1, true, "test");
            System.out.println("赋值后:" +
                    ClassLayout.parseInstance(b).
                            toPrintable());
        }
    
        static class Hero {
            int i;
            boolean flag;
            String str;
    
            public Hero() {
    
            }
    
            public Hero(int i, boolean flag, String str) {
                this.i = i;
                this.flag = flag;
                this.str = str;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在这里插入图片描述
    对象的大小 = 12对象头 + 4*3的实例数据 + 0的填充 = 24bytes

    对象头存储信息分析

    1 如果是空对象

     Object obj = new Object();
    
    • 1

    在这里插入图片描述
    2 带锁的对象
    可以看一下这篇文章关于头的顺序

    • 偏向锁
    // java 默认5s以上才会开启偏向锁
    Thread.sleep(5001);
    Object lock = new Object();
    printObj(lock, 1);
    synchronized (lock) {
        printObj(lock, 2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    • 轻量级锁
    Thread.sleep(5001);
       Object lock = new Object();
       printObj(lock, 1);
       synchronized (lock) {
           printObj(lock, 2);
       }
       Thread.sleep(1000);
       new Thread(() -> {
           synchronized (lock) {
               System.out.println("get lock one");
               printObj(lock, 3);
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
           }
       }).start();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这里我们有Main线程和新开的一个线程来竞争资源,所以就会升级为一个轻量级锁。
    在这里插入图片描述

    • 重量级锁
    for (int i = 0; i < 10; i ++) {
     new Thread(() -> {
         synchronized (lock) {
             try {
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
                 throw new RuntimeException(e);
             }
             System.out.println("get lock three");
         }
     }).start();
      printObj(lock, 5);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    对象的访问

    有两种方式:

    1. 句柄:稳定,对象被移动只要修改句柄中的地址
      在这里插入图片描述

    2. 直接指针:访问速度快,节省了一次指针定位的开销
      在这里插入图片描述
      对象类型数据存储的是对象的元信息,比如有哪些字段,那些方法

  • 相关阅读:
    密码学-SHA-1算法
    一张图搞懂微服务架构设计
    设计模式 煎饼果子和装饰者模式
    一个美观且功能丰富的 .NET 控制台应用程序开源库
    恩智浦为稳固地位,将扩大投资4国家 | 百能云芯
    vivo霍金实验平台设计与实践-平台产品系列02
    【数据结构】排序算法复杂度 及 稳定性分析 【图文详解】
    最新美国斯坦福大学2023全球前2%科学家(中国内地)榜单
    获得列表中的空的段的起始位置(Python)
    阿里云短信验证接口调用
  • 原文地址:https://blog.csdn.net/qq_43259860/article/details/136127654