当前位置: 首页 > news >正文

synchronized内存布局图(bit 精确位置)

64位 HotSpot JDK 8下的对象头精确 bit 位布局图反编译验证示例为例


一、64位 JDK 8 对象头(Mark Word)精确 bit 位布局

以下基于HotSpot 64位 VM,默认开启指针压缩(-XX:+UseCompressedOops-XX:+UseCompressedClassPointers),此时 Mark Word 占8 字节,Klass Pointer 占4 字节,对象头共 12 字节。

Mark Word 各状态 bit 位拆解(低位在右)

1. 无锁状态(biased_lock=0,lock=01)
|--------------------------------------------------| | unused:25 | identity_hashcode:31 | age:4 | 0 | 01 | |--------------------------------------------------| bits 63-39 bits 38-8 bits 7-4 3 2-0
  • bit 0–1:锁标志位01(无锁/偏向未生效)
  • bit 2:偏向锁标记0(无锁)
  • bit 3–6:分代年龄(age)
  • bit 7–38:对象哈希码(如果已调用System.identityHashCode()
  • bit 39–63:未使用(或存 GC 元信息)

2. 偏向锁状态(biased_lock=1,lock=01)
|--------------------------------------------------------------| | thread:54 | epoch:2 | unused:1 | age:4 | 1 | 01 | |--------------------------------------------------------------| bits 63-10 bits 9-8 bit 7 bits 6-3 2 1-0
  • bit 0–1:锁标志位01
  • bit 2:偏向锁标记1(表示是偏向锁状态)
  • bit 3–6:分代年龄(age)
  • bit 7:未使用
  • bit 8–9:偏向锁 epoch(用于批量重偏向)
  • bit 10–63:持有偏向锁的线程 ID(54 bits)

3. 轻量级锁状态(lock=00)
|--------------------------------------------------| | 指向 Lock Record 的指针 | 00 | |--------------------------------------------------| bits 63-2 1-0
  • bit 0–100
  • bit 2–63:指向当前线程栈中Lock Record的指针(62 bits 可用,因为指针最后2位为0,实际存储时右移2位)

4. 重量级锁状态(lock=10)
|--------------------------------------------------| | 指向 ObjectMonitor 的指针 | 10 | |--------------------------------------------------| bits 63-2 1-0
  • bit 0–110
  • bit 2–63:指向 C++ 对象ObjectMonitor的指针

5. GC 标记(lock=11)
|--------------------------------------------------| | GC 标记信息 | 11 | |--------------------------------------------------| bits 63-2 1-0
  • bit 0–111(表示对象被 GC 标记,具体含义取决于 GC 算法)

图示总览(一个容易记忆的图表)

┌─────────────────────────────────────────────────────────────┐ │ Mark Word (64 bits) │ ├──────────────┬─────────────────────┬──────────┬─────────────┤ │ 无锁(001) │ unused:25 | hash:31 │ age:4 │ 0 │ 01 │ ├──────────────┼─────────────────────┼──────────┼─────────────┤ │ 偏向(101) │ thread:54 | ep:2 │ age:4 │ 1 │ 01 │ ├──────────────┼─────────────────────┼──────────┼─────────────┤ │ 轻量级(00) │ ptr to LockRecord (62 bits) │ 00 │ ├──────────────┼─────────────────────┼──────────┼─────────────┤ │ 重量级(10) │ ptr to ObjectMonitor (62 bits)│ 10 │ ├──────────────┼─────────────────────┼──────────┼─────────────┤ │ GC标记(11) │ GC info (62 bits) │ 11 │ └──────────────┴─────────────────────┴──────────┴─────────────┘

其中age(4 bits)表示对象在年轻代中存活次数,达到阈值 15 将晋升到老年代。


二、反编译验证示例(javap 查看 monitorenter/monitorexit)

1. 编写简单同步代码

publicclassSynchronizedDemo{privatestaticfinalObjectlock=newObject();publicstaticvoidmain(String[]args){synchronized(lock){System.out.println("Hello synchronized");}}}

2. 编译并反编译

javac SynchronizedDemo.java javap-c-vSynchronizedDemo.class

3. 关键字节码输出(截取 main 方法)

publicstaticvoidmain(java.lang.String[]);Code:0:getstatic #2// lock3:dup4:astore_15:monitorenter// <-- 进入 synchronized6:getstatic #3// System.out9:ldc #4// "Hello synchronized"11:invokevirtual #5// println14:aload_115:monitorexit// <-- 退出 synchronized16:goto2419:astore_220:aload_121:monitorexit// <-- 异常时的退出22:aload_223:athrow24:returnExceptiontable:fromtotargettype61619any
  • monitorentermonitorexit指令是 synchronized 的字节码基础。
  • 实际锁升级、对象头修改由 JVM 内部在运行时完成,字节码层面看不到锁状态。

三、JOL(Java Object Layout)验证对象头变化

JOL 是 OpenJDK 提供的工具,可以直接打印对象内存布局,直观看到 Mark Word 的变化。

1. Maven 依赖

<dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.17</version></dependency>

2. 验证无锁 → 偏向锁 → 轻量锁 → 重量锁

importorg.openjdk.jol.info.ClassLayout;importorg.openjdk.jol.vm.VM;publicclassJolExample{publicstaticvoidmain(String[]args)throwsInterruptedException{// 等待偏向锁延迟过去(默认4秒)Thread.sleep(5000);Objectobj=newObject();// 无锁状态(实际是偏向未锁定,但JOL会显示为偏向锁不可用?)System.out.println("=== 刚创建,无锁 ===");System.out.println(ClassLayout.parseInstance(obj).toPrintable());// 加偏向锁(一个线程加锁)synchronized(obj){System.out.println("\n=== 偏向锁 ===");System.out.println(ClassLayout.parseInstance(obj).toPrintable());}// 另一个线程来竞争,导致升级为轻量锁(需要另外的线程,简单场景可用两个线程演示)Threadt=newThread(()->{synchronized(obj){System.out.println("\n=== 其他线程获得锁(轻量锁/重量锁)===");System.out.println(ClassLayout.parseInstance(obj).toPrintable());}});t.start();t.join();// 再main线程加锁,可能升级为重量锁(多竞争几次)for(inti=0;i<10;i++){newThread(()->{synchronized(obj){try{Thread.sleep(10);}catch(InterruptedExceptione){}}}).start();}Thread.sleep(100);synchronized(obj){System.out.println("\n=== 高竞争后,可能变为重量锁 ===");System.out.println(ClassLayout.parseInstance(obj).toPrintable());}}}

3. 输出示例(节选关键字段)

=== 刚创建,无锁 === # 运行状态(无锁): OFF SZ TYPE DESCRIPTION 0 8 (object header) 01 00 00 00 00 00 00 00 (未偏向) 8 4 (class pointer) 12 4 (padding) === 偏向锁 === # 偏向状态: 0 8 (object header) 05 30 f2 4a 19 02 00 00 (末尾 05 表示偏向锁) === 其他线程获得锁(轻量锁)=== # 轻量锁状态(末尾 00 或 f0): 0 8 (object header) a8 f4 1f 78 71 7f 00 00 (末尾 bit 为 00) === 高竞争后,重量锁 === # 重量锁状态(末尾 3a 或 ba): 0 8 (object header) 3a 0a 56 1a 00 00 00 00 (末尾 10)

注意:实际十六进制数据中,最后两个 bit(低位)是锁标志:

  • 01且第3 bit 为 0 → 无锁
  • 05(00000101) → 偏向锁(101)
  • 00f0等,最后两位 00 → 轻量锁
  • 3a(00111010)最后两位10→ 重量锁

四、如何确定当前 JVM 使用的是哪种锁?

可以通过打印系统属性或者 JVM 参数查看:

java-XX:+PrintFlagsFinal|grepBiasedLocking

结果示例:

bool UseBiasedLocking=true{product}intx BiasedLockingStartupDelay=4000{product}

若偏移锁关闭,则对象创建后直接为轻量级锁的“无锁可偏向”状态,实际不太一样,但底层仍会经历 “无锁 → 轻量锁 → 重量锁”。


五、小结

  • 精确 bit 图:上面已给出 64 位下每个状态的使用位。
  • 验证方法
    • 字节码:javap看到monitorenter/exit
    • 内存布局:JOL打印对象头十六进制,对照锁标志位判断当前锁状态。
http://www.jsqmd.com/news/767788/

相关文章:

  • Promptr:用自然语言指令自动化重构代码的AI工具实践指南
  • 在github上快速部署taotoken的python调用示例
  • 千问 LeetCode 2127.参加会议的最多员工数 Python3实现
  • AI智能体全栈开发框架解析:从核心架构到生产部署
  • 免费实时提升动漫画质:Anime4K超分辨率技术完整指南
  • 车载Docker轻量化不是删RUN指令!(嵌入式Linux内核模块按需加载+initramfs动态注入技术详解)
  • 别再搞混了!一文讲透CGCS2000、WGS84和ITRF框架的区别与联系(附实用转换思路)
  • AI工具搭建自动化视频生成Save Video
  • 用J-Link Commander和逻辑分析仪,一步步拆解Cortex-M4的JTAG-DAP通信时序
  • Windows系统级光标美化:完整移植macOS光标方案实战指南
  • Verilog时序控制与硬件设计实践指南
  • CUDA开发实战:从内存管理到内核优化的核心技能解析
  • 编码能力超越ClaudeCode,最新国内用户一键接入Codex小白快速入门教程
  • 别急着改环境变量!nvidia-smi命令失效,先试试这几个更简单的排查方法
  • PotPlayer字幕翻译插件终极配置指南:百度翻译API快速上手教程
  • 2025最权威的五大降重复率工具实际效果
  • 保姆级教程:在RK3588平台上配置CIF链路监控,解决MIPI断流问题
  • 马尔可夫链蒙特卡洛(MCMC)算法
  • GRADFILTERING:基于梯度信噪比的智能数据选择方法
  • 边缘AI的去中心化协作学习技术解析
  • Fan Control深度解析:Windows智能风扇控制架构与技术实现
  • 2025届最火的十大降AI率神器解析与推荐
  • Unlocker 3.0终极指南:在普通PC上免费运行macOS虚拟机的完整教程
  • AI应用工程化实战:基于harness-kit构建生产级智能客服系统
  • 树莓派CM5载板PoE供电方案对比与工业应用指南
  • 基于GPT-4 Vision的实时视觉对话应用开发实战
  • 博物馆项目实战:用Unity给陶艺建模,我是如何搞定动态网格生成与顶点操控的?
  • AI工具搭建自动化视频生成Load Video
  • 用ConvNeXt-Tiny搞定花卉分类:从数据集制作到模型评估的完整PyTorch实战
  • browser39:现代浏览器自动化工具的设计原理与实战应用