JAVA 对象头MarkWord

JAVA 对象头MarkWord

最近在并发编程的学习中,接触到了JAVA对象头中的MarkWord. 在此做下笔记,也和小伙伴们分享一下,共同进步!

MarkWord介绍

MarkWord是Java对象存储在内存中的一部分信息.
在32位系统中使用32位存储, 64位系统中使用64存储.以下是来自Hotspot中源码注释!

HotSpot源码注释中给出的是大端存储下的Layout.
我们平时电脑都是小端存储的,所以后续的测试结果中会出现和下图不匹配的情况!

关于大小端存储可以参考下图
图片

HotSpot源码注释

// The markOop describes the header of an object.
//
// Note that the mark is not a real oop but just a word.
// It is placed in the oop hierarchy for historical reasons.
//
// Bit-format of an object header (most significant first, big endian layout below):
//
//  32 bits:
//  --------
//  hash:25 ------------>| age:4    biased_lock:1 lock:2 (normal object)
//  JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)
//  size:32 ------------------------------------------>| (CMS free block)
//  PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
//
//  64 bits:
//  --------
//  unused:25 hash:31 -->| unused:1   age:4    biased_lock:1 lock:2 (normal object)
//  JavaThread*:54 epoch:2 unused:1   age:4    biased_lock:1 lock:2 (biased object)
//  PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
//  size:64 ----------------------------------------------------->| (CMS free block)
//
//  unused:25 hash:31 -->| cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && normal object)
//  JavaThread*:54 epoch:2 cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && biased object)
//  narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
//  unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)

64位系统中,MarkWord结构如下
在这里插入图片描述

学习对象头,我们需要依赖一个工具JOL (JAVA OBJECT LAYOUT)可以通过pom.xml进行引入

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.14</version>
    <scope>provided</scope>
</dependency>

001 无锁,不可偏向状态

@Test
public void testUnLock() throws InterruptedException {

    System.out.println("第一次结果: ");
    System.out.println(ClassLayout.parseInstance(new Object()).toPrintable());

    Thread.sleep(4000);

    System.out.println("第二次结果: ");
    System.out.println(ClassLayout.parseInstance(new Object()).toPrintable());
}

图片

101 无锁,可偏向状态

@Test
public void testBiasedUnLock() throws InterruptedException {

    //  关闭延迟开启偏向锁
    //  -XX:BiasedLockingStartupDelay=0
    Object o = new Object();
    System.out.println("第一次结果: ");
    System.out.println(ClassLayout.parseInstance(o).toPrintable());

    int hashCode = o.hashCode();

    System.out.println("第二次结果: ");
    System.out.println(ClassLayout.parseInstance(o).toPrintable());

}

图片

101 偏向锁

static final Object lock = new Object();

@Test
public void testBiasedLock() {
    //  关闭延迟开启偏向锁
    //  -XX:BiasedLockingStartupDelay=0

    System.out.println("第一次结果: ");
    System.out.println(ClassLayout.parseInstance(lock).toPrintable());
    synchronized (lock){
        System.out.println("加锁后结果: ");
        System.out.println(ClassLayout.parseInstance(lock).toPrintable());
    }
    System.out.println("解锁后结果: ");
    System.out.println(ClassLayout.parseInstance(lock).toPrintable());
}

图片

00 轻量锁

static final Object lock = new Object();

@Test
public void testLock() {
    //  关闭延迟开启偏向锁
    //  -XX:BiasedLockingStartupDelay=0
    synchronized (lock){
        System.out.println("主线程加锁: ");
        System.out.println(ClassLayout.parseInstance(lock).toPrintable());
    }

    new Thread(()->{
        synchronized (lock){
            System.out.println("子线程加锁: ");
            System.out.println(ClassLayout.parseInstance(lock).toPrintable());
        }
    }).start();
}

图片

10 重量锁

static final Object lock = new Object();
    
@Test
public void testInflatedLock() throws InterruptedException {

    Thread t1 = new Thread(() -> {
        synchronized (lock) {
            System.out.println("t1加锁: ");
            System.out.println(ClassLayout.parseInstance(lock).toPrintable());
        }
    });

    Thread t2 = new Thread(() -> {
        synchronized (lock) {
            System.out.println("t2加锁: ");
            System.out.println(ClassLayout.parseInstance(lock).toPrintable());
        }
    });

    t1.start();
    t2.start();

    // 等待t1, t2执行完, 否则无法打印
    t1.join();
    t2.join();
}

图片

11 GC标记清除

由于标记清除是指此对象已被垃圾回收器标记成可回收对象.所以演示不出来.

图片
图片

Java对象头中的`mark word`是对象内存布局中的一个关键组成部分,主要用于存储对象的运行时元数据信息。其结构和作用因虚拟机实现和对象状态的不同而有所变化,但通常包括以下几类信息: - **哈希码(Hash Code)**:对象的唯一标识码,用于支持Java的`hashCode()`方法。 - **GC分代年龄(GC Age)**:用于标记对象在垃圾收集器中的生存周期,辅助分代垃圾回收策略。 - **锁状态标志(Lock State)**:记录对象的同步状态,例如是否被加锁、锁的类型(偏向锁、轻量级锁、重量级锁等)。 - **线程持有的锁(Thread ID)**:在偏向锁的情况下,记录持有锁的线程ID。 - **指向锁记录的指针(Pointer to Lock Record)**:在轻量级锁机制中,`mark word`会指向栈中锁记录的位置。 - **指向重量级锁的指针(Pointer to Monitor)**:当对象进入重量级锁状态时,`mark word`会指向一个与该对象关联的监视器(Monitor)。 在64位JVM中,`mark word`通常占用8字节,其具体布局可能如下(不同JVM实现可能略有差异): | 状态 | 结构描述 | |----------------|----------| | 未锁定(Unlocked) | 25位哈希码 + 4位GC年龄 + 1位偏向锁标志 + 2位锁标志 | | 偏向锁(Biased) | 54位线程ID + 2位偏向时间戳 + 1位偏向锁标志 + 2位锁标志 | | 轻量级锁(Lightweight Locked) | 62位指向锁记录的指针 + 2位锁标志 | | 重量级锁(Inflated) | 62位指向监视器的指针 + 2位锁标志 | `mark word`的作用主要体现在以下几个方面: - **对象标识**:存储对象的哈希码,确保对象在集合类(如`HashMap`、`HashSet`)中的唯一性和快速查找[^1]。 - **垃圾回收**:通过记录GC分代年龄,协助垃圾回收器判断对象的存活状态,优化内存管理效率。 - **同步机制**:支持Java的线程同步机制,通过锁状态标志和相关指针实现不同级别的锁优化,如偏向锁、轻量级锁和重量级锁,提高并发性能[^1]。 ### 示例代码:对象头与锁状态变化 ```java public class MarkWordExample { private static Object obj = new Object(); public static void main(String[] args) { // 查看对象头信息(需依赖JOL库) System.out.println(org.openjdk.jol.info.ClassLayout.parseInstance(obj).toPrintable()); // 加锁后查看对象头状态变化 synchronized (obj) { System.out.println("After locking:"); System.out.println(org.openjdk.jol.info.ClassLayout.parseInstance(obj).toPrintable()); } } } ``` 运行上述代码需要引入JOL(Java Object Layout)库,它可以帮助开发者查看Java对象在内存中的实际布局,包括`mark word`的变化情况。 ### 相关问题 1. Java对象头在不同JVM实现中有哪些差异? 2. 如何使用JOL工具分析Java对象的内存布局? 3. Java中的偏向锁、轻量级锁和重量级锁有何区别? 4. `mark word`在多线程环境下如何支持锁优化? 5. `mark word`是否会影响Java对象的性能?
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值