Java对象内存布局和对象头

本文详细探讨了Java对象在内存中的布局,包括对象头的MarkWord结构,其在对象创建、垃圾回收和锁状态中的作用。讲解了对象存储在栈和堆中的区别,以及对象头如何记录哈希码、锁状态和垃圾回收信息。同时阐述了轻量级锁和重量级锁的状态转换,展示了对象在不同锁状态下的内存占用情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java对象内存布局和对象头

对象的存储位置

创建一个object对象,Object o = new Object();,首先我们要明确知道创建对象的那一行代码的存储位置,

Object相当于一个Object类的模板,类加载的时候放在方法区,存放类的信息

o:在方法体中,随着方法的调用,存储在栈中栈帧信息中,

tips:栈帧包括局部变量表,操作数栈,动态链接,返回地址

new Object():创建的对象信息放在堆空间中

对象的内存布局

了解到了对象的存储位置,这时我们要知道对象在堆中存放哪些信息?

对象在堆内存中存储布局可以划分为三个:对象头,实例数据,填充属性

  1. 对象头:包括Markword和类型指针

     一个对象中都应该包含一下:
    
  • hashcode值,自己的hash值,记录在内存中什么地方
  • 给对象可以加锁,标记对象有没有加锁
  • 进行垃圾回收时,要对对象进行标记是否为垃圾对象还有它的垃圾回收次数

这些基本信息在对象头中markword都记录着,比如GC标记信息,GC次数,同步锁标记,偏向锁持有者,hashcode值

2.实例数据:可以认为是对象中的一些数据,比如String id;

3.填充属性:当创建的对象占用内存大小不为8个字节的倍数,会对对象的内存占用补充为8的倍数

创建对象的内存占用大小

在64位操作系统当中,对象头中Mark word为8字节,类型指针为8字节,在没有实例数据的情况下,占用内存大小为16个字节

Mark Word结构

  • hash: 保存对象的哈希码。运行期间调用System.identityHashCode()来计算,延迟计算,并把结果赋值到这里。
  • age: 保存对象的分代年龄。表示对象被GC的次数,当该次数到达阈值的时候,对象就会转移到老年代。
  • biased_lock: 偏向锁标识位。由于无锁和偏向锁的锁标识都是 01,没办法区分,这里引入一位的偏向锁标识位。
  • lock: 锁状态标识位。区分锁状态,比如11时表示对象待GC回收状态, 只有最后2位锁标识(11)有效。
  • JavaThread*: 保存持有偏向锁的线程ID。偏向模式的时候,当某个线程持有对象的时候,对象这里就会被置为该线程的ID。 在后面的操作中,就无需再进行尝试获取锁的动作。这个线程ID并不是JVM分配的线程ID号,和Java Thread中的ID是两个概念。
  • epoch: 保存偏向时间戳。偏向锁在CAS锁操作过程中,偏向性标识,表示对象更偏向哪个锁。

在这里插入图片描述

Markword分布图:对象布局,GC回收和后面锁升级就是对象标记MarkWord里面标志位的变换

25+31+1+4+1+2 = 64位

在这里插入图片描述

偏向锁状态时:当线程第一次访问同步代码块并获取锁时,虚拟机将会把对象头中的标志位设为01,同时使用CAS操作把获取到这个锁的线程id记录在对象的Markword中

轻量级状态:将对象头中的数据都置换为指向栈中锁的记录的指针

重量级状态:将对象头中的数据都置换为指向重量级锁的指针

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值