资讯动态

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

发布时间:2026/9/9 8:53:52 来源:尧图企业网站定制
以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_lock0lock01|--------------------------------------------------| | unused:25 | identity_hashcode:31 | age:4 | 0 | 01 | |--------------------------------------------------| bits 63-39 bits 38-8 bits 7-4 3 2-0bit 0–1锁标志位01无锁/偏向未生效bit 2偏向锁标记0无锁bit 3–6分代年龄agebit 7–38对象哈希码如果已调用System.identityHashCode()bit 39–63未使用或存 GC 元信息2. 偏向锁状态biased_lock1lock01|--------------------------------------------------------------| | thread:54 | epoch:2 | unused:1 | age:4 | 1 | 01 | |--------------------------------------------------------------| bits 63-10 bits 9-8 bit 7 bits 6-3 2 1-0bit 0–1锁标志位01bit 2偏向锁标记1表示是偏向锁状态bit 3–6分代年龄agebit 7未使用bit 8–9偏向锁 epoch用于批量重偏向bit 10–63持有偏向锁的线程 ID54 bits3. 轻量级锁状态lock00|--------------------------------------------------| | 指向 Lock Record 的指针 | 00 | |--------------------------------------------------| bits 63-2 1-0bit 0–100bit 2–63指向当前线程栈中Lock Record的指针62 bits 可用因为指针最后2位为0实际存储时右移2位4. 重量级锁状态lock10|--------------------------------------------------| | 指向 ObjectMonitor 的指针 | 10 | |--------------------------------------------------| bits 63-2 1-0bit 0–110bit 2–63指向 C 对象ObjectMonitor的指针5. GC 标记lock11|--------------------------------------------------| | GC 标记信息 | 11 | |--------------------------------------------------| bits 63-2 1-0bit 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 │ └──────────────┴─────────────────────┴──────────┴─────────────┘其中age4 bits表示对象在年轻代中存活次数达到阈值 15 将晋升到老年代。二、反编译验证示例javap 查看 monitorenter/monitorexit1. 编写简单同步代码publicclassSynchronizedDemo{privatestaticfinalObjectlocknewObject();publicstaticvoidmain(String[]args){synchronized(lock){System.out.println(Hello synchronized);}}}2. 编译并反编译javac SynchronizedDemo.java javap-c-vSynchronizedDemo.class3. 关键字节码输出截取 main 方法publicstaticvoidmain(java.lang.String[]);Code:0:getstatic #2// lock3:dup4:astore_15:monitorenter// -- 进入 synchronized6:getstatic #3// System.out9:ldc #4// Hello synchronized11:invokevirtual #5// println14:aload_115:monitorexit// -- 退出 synchronized16:goto2419:astore_220:aload_121:monitorexit// -- 异常时的退出22:aload_223:athrow24:returnExceptiontable:fromtotargettype61619anymonitorenter和monitorexit指令是 synchronized 的字节码基础。实际锁升级、对象头修改由 JVM 内部在运行时完成字节码层面看不到锁状态。三、JOLJava Object Layout验证对象头变化JOL 是 OpenJDK 提供的工具可以直接打印对象内存布局直观看到 Mark Word 的变化。1. Maven 依赖dependencygroupIdorg.openjdk.jol/groupIdartifactIdjol-core/artifactIdversion0.17/version/dependency2. 验证无锁 → 偏向锁 → 轻量锁 → 重量锁importorg.openjdk.jol.info.ClassLayout;importorg.openjdk.jol.vm.VM;publicclassJolExample{publicstaticvoidmain(String[]args)throwsInterruptedException{// 等待偏向锁延迟过去默认4秒Thread.sleep(5000);ObjectobjnewObject();// 无锁状态实际是偏向未锁定但JOL会显示为偏向锁不可用System.out.println( 刚创建无锁 );System.out.println(ClassLayout.parseInstance(obj).toPrintable());// 加偏向锁一个线程加锁synchronized(obj){System.out.println(\n 偏向锁 );System.out.println(ClassLayout.parseInstance(obj).toPrintable());}// 另一个线程来竞争导致升级为轻量锁需要另外的线程简单场景可用两个线程演示ThreadtnewThread(()-{synchronized(obj){System.out.println(\n 其他线程获得锁轻量锁/重量锁);System.out.println(ClassLayout.parseInstance(obj).toPrintable());}});t.start();t.join();// 再main线程加锁可能升级为重量锁多竞争几次for(inti0;i10;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 → 无锁0500000101 → 偏向锁10100或f0等最后两位 00 → 轻量锁3a00111010最后两位10→ 重量锁四、如何确定当前 JVM 使用的是哪种锁可以通过打印系统属性或者 JVM 参数查看java-XX:PrintFlagsFinal|grepBiasedLocking结果示例bool UseBiasedLockingtrue{product}intx BiasedLockingStartupDelay4000{product}若偏移锁关闭则对象创建后直接为轻量级锁的“无锁可偏向”状态实际不太一样但底层仍会经历 “无锁 → 轻量锁 → 重量锁”。五、小结精确 bit 图上面已给出 64 位下每个状态的使用位。验证方法字节码javap看到monitorenter/exit内存布局JOL打印对象头十六进制对照锁标志位判断当前锁状态。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价