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.jol</groupId>
	<artifactId>jol-core</artifactId>
	<version>0.9</version>
</dependency>
 Object o = new Object();
        System.out.println("new Object:" +
                ClassLayout.parseInstance(o).toPrintable());

在这里插入图片描述
注:首先对象头是包含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;
        }
    }
}

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

对象头存储信息分析

1 如果是空对象

 Object obj = new Object();

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

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

在这里插入图片描述

  • 轻量级锁
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();

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

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值