性能文章>13 轻量级锁的重入 以及 线程1获取轻量级锁并释放线程2获取锁 的调试>

13 轻量级锁的重入 以及 线程1获取轻量级锁并释放线程2获取锁 的调试原创

1年前
340912

前言 

09 给对象添加偏向锁的调试

10 偏向锁的退出的调试

11 偏向锁的重入 以及 线程1获取偏向锁并释放线程2获取锁 的调试

12 给对象添加轻量级锁的调试

呵呵 接着前几篇 

 

本文调试一下 一下的几个场景

1. 轻量级的重入

2. 线程1添加了轻量级并释放, 线程2来获取锁  

 

 

一下内容基于 jdk9 + lldb-1001.0.13.3 

另外一下 运行时数据可能是来自于多次调试, 可能会存在运行时数据 对不上的情况, 但是的条理逻辑会在文字中描述清楚的 

备注 : 以下调试 增加了vm参数 : -XX:-UseBiasedLocking

 

 

轻量级锁重入的测试用例

package com.hx.test04;
 
/**
 * Test26SynchronizeReentrantObject
 *
 * @author Jerry.X.He <970655147@qq.com>
 * @version 1.0
 * @date 2020-04-03 15:14
 */
public class Test26SynchronizeReentrantObject implements Cloneable {
 
  // identStr
  private String identStr = "xyz";
  int f01;
  int f02;
  int f03;
  int f04;
  int f05;
 
  // Test26SynchronizeReentrantObject
  public static void main(String[] args) throws Exception {
 
    Test26SynchronizeReentrantObject lockObj = new Test26SynchronizeReentrantObject();
 
    synchronized (lockObj) {
      synchronized (lockObj) {
 
//        Test26SynchronizeReentrantObject cloned = (Test26SynchronizeReentrantObject) lockObj.clone();
//        System.out.println(lockObj.identStr);
 
      }
    }
 
  }
 
}

 

对应的字节码信息如下, 下面参照可能需要使用到 

master:classes jerry$ javap -c com/hx/test04/Test26SynchronizeReentrantObject.class 
Compiled from "Test26SynchronizeReentrantObject.java"
public class com.hx.test04.Test26SynchronizeReentrantObject implements java.lang.Cloneable {
  int f01;
 
  int f02;
 
  int f03;
 
  int f04;
 
  int f05;
 
  public com.hx.test04.Test26SynchronizeReentrantObject();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: ldc           #2                  // String xyz
       7: putfield      #3                  // Field identStr:Ljava/lang/String;
      10: return
 
  public static void main(java.lang.String[]) throws java.lang.Exception;
    Code:
       0: new           #4                  // class com/hx/test04/Test26SynchronizeReentrantObject
       3: dup
       4: invokespecial #5                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: dup
      10: astore_2
      11: monitorenter
      12: aload_1
      13: dup
      14: astore_3
      15: monitorenter
      16: aload_3
      17: monitorexit
      18: goto          28
      21: astore        4
      23: aload_3
      24: monitorexit
      25: aload         4
      27: athrow
      28: aload_2
      29: monitorexit
      30: goto          40
      33: astore        5
      35: aload_2
      36: monitorexit
      37: aload         5
      39: athrow
      40: return
    Exception table:
       from    to  target type
          16    18    21   any
          21    25    21   any
          12    30    33   any
          33    37    33   any
}

 

 

轻量级锁重入的调试

(lldb) p _active_table._table[9][194]
(address) $0 = 0x00000001048cd600 "XH;"
(lldb) b 0x00000001048cd600
Breakpoint 3: address = 0x00000001048cd600
(lldb) c
Process 1019 resuming
Process 1019 stopped
* thread #5, stop reason = breakpoint 3.1
    frame #0: 0x00000001048cd600
->  0x1048cd600: popq   %rax
    0x1048cd601: cmpq   (%rax), %rax
    0x1048cd604: xorl   %esi, %esi
    0x1048cd606: movq   -0x48(%rbp), %rcx
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
       rax = 0x0000000747bb8798
       rbx = 0x00000000000000c2
       rcx = 0x0000000000000008
       rdx = 0x0000000747bb87b8
       rdi = 0x000000010100f220
       rsi = 0x000070000a2595c0
       rbp = 0x000070000a259670
       rsp = 0x000070000a259620
        r8 = 0x0000000000000000
        r9 = 0x0000000000000020
       r10 = 0x000000010430b270  libjvm.dylib`TemplateInterpreter::_active_table + 18432
       r11 = 0x00006fff09249400
       r12 = 0x0000000000000000
       r13 = 0x000000011c96ff93
       r14 = 0x000070000a2596a8
       r15 = 0x000000010100f220
       rip = 0x00000001048cd600
    rflags = 0x0000000000000206
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 0x0000000000000000

(lldb) p ((oopDesc*)0x0000000747bb8798)->print()
com.hx.test04.Test26SynchronizeReentrantObject 
{0x0000000747bb8798} - klass: 'com/hx/test04/Test26SynchronizeReentrantObject'
 - ---- fields (total size 5 words):
 - 'f01' 'I' @12  0
 - 'f02' 'I' @16  0
 - 'f03' 'I' @20  0
 - 'f04' 'I' @24  0
 - 'f05' 'I' @28  0
 - private 'identStr' 'Ljava/lang/String;' @32  "xyz"{0x0000000747bb87c0} (e8f770f8 0)
(lldb) p ((oopDesc*)0x0000000747bb8798)->has_locker()
error: no member named 'has_locker' in 'oopDesc'
(lldb) p ((oopDesc*)0x0000000747bb8798)->mark()->has_locker()
(bool) $1 = false
(lldb) x 0x000070000a259620
0x70000a259620: 98 87 bb 47 07 00 00 00 28 96 25 0a 00 70 00 00  ..?G....(.%..p..
0x70000a259630: 8c ff 96 1c 01 00 00 00 a8 96 25 0a 00 70 00 00  .?......?.%..p..

// continue, 之后 断点停留在了 第二个 monitorenter
(lldb) c
Process 1019 resuming
Process 1019 stopped
* thread #5, stop reason = breakpoint 3.1
    frame #0: 0x00000001048cd600
->  0x1048cd600: popq   %rax
    0x1048cd601: cmpq   (%rax), %rax
    0x1048cd604: xorl   %esi, %esi
    0x1048cd606: movq   -0x48(%rbp), %rcx
Target 0: (java) stopped.
(lldb) p ((oopDesc*)0x0000000747bb8798)->mark()->has_locker()
(bool) $2 = true
(lldb) re r
General Purpose Registers:
       rax = 0x0000000747bb8798
       rbx = 0x00000000000000c2
       rcx = 0x0000000747bb8798
       rdx = 0x000070000a259628
       rdi = 0x000000010100f220
       rsi = 0x000070000a259618
       rbp = 0x000070000a259670
       rsp = 0x000070000a259610
        r8 = 0x0000000000000000
        r9 = 0x0000000000000020
       r10 = 0x000000010430b270  libjvm.dylib`TemplateInterpreter::_active_table + 18432
       r11 = 0x00006fff09249400
       r12 = 0x0000000000000000
       r13 = 0x000000011c96ff97
       r14 = 0x000070000a2596a8
       r15 = 0x000000010100f220
       rip = 0x00000001048cd600
    rflags = 0x0000000000000202
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 0x0000000000000000

(lldb) x 0x000070000a259610 -c 0x30
0x70000a259610: 98 87 bb 47 07 00 00 00 01 00 00 00 00 00 00 00  ..?G............
0x70000a259620: 98 87 bb 47 07 00 00 00 18 96 25 0a 00 70 00 00  ..?G......%..p..
0x70000a259630: 94 ff 96 1c 01 00 00 00 a8 96 25 0a 00 70 00 00  .?......?.%..p..
(lldb) b 0x1048cd663
Breakpoint 4: address = 0x00000001048cd663
(lldb) c
Process 1019 resuming
Process 1019 stopped
* thread #5, stop reason = breakpoint 4.1
    frame #0: 0x00000001048cd663
->  0x1048cd663: movq   0x8(%rsi), %rcx
    0x1048cd667: movl   $0x1, %eax
    0x1048cd66c: orq    (%rcx), %rax
    0x1048cd66f: movq   %rax, (%rsi)
Target 0: (java) stopped.
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x00000001048cd667
->  0x1048cd667: movl   $0x1, %eax
    0x1048cd66c: orq    (%rcx), %rax
    0x1048cd66f: movq   %rax, (%rsi)
    0x1048cd672: lock   
Target 0: (java) stopped.
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x00000001048cd66c
->  0x1048cd66c: orq    (%rcx), %rax
    0x1048cd66f: movq   %rax, (%rsi)
    0x1048cd672: lock   
    0x1048cd673: cmpxchgq %rsi, (%rcx)
Target 0: (java) stopped.
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x00000001048cd66f
->  0x1048cd66f: movq   %rax, (%rsi)
    0x1048cd672: lock   
    0x1048cd673: cmpxchgq %rsi, (%rcx)
    0x1048cd677: je     0x1048cd8f0
Target 0: (java) stopped.
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x00000001048cd672
->  0x1048cd672: lock   
    0x1048cd673: cmpxchgq %rsi, (%rcx)
    0x1048cd677: je     0x1048cd8f0
    0x1048cd67d: subq   %rsp, %rax
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
       rax = 0x000070000a259619
       rbx = 0x00000000000000c2
       rcx = 0x0000000747bb8798
       rdx = 0x000070000a259628
       rdi = 0x000000010100f220
       rsi = 0x000070000a259608
       rbp = 0x000070000a259670
       rsp = 0x000070000a259608
        r8 = 0x0000000000000000
        r9 = 0x0000000000000020
       r10 = 0x000000010430b270  libjvm.dylib`TemplateInterpreter::_active_table + 18432
       r11 = 0x00006fff09249400
       r12 = 0x0000000000000000
       r13 = 0x000000011c96ff98
       r14 = 0x000070000a2596a8
       r15 = 0x000000010100f220
       rip = 0x00000001048cd672
    rflags = 0x0000000000000202
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 0x0000000000000000

(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x00000001048cd677
->  0x1048cd677: je     0x1048cd8f0
    0x1048cd67d: subq   %rsp, %rax
    0x1048cd680: andq   $-0xff9, %rax             ; imm = 0xF007 
    0x1048cd687: movq   %rax, (%rsi)
Target 0: (java) stopped.
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x00000001048cd67d
->  0x1048cd67d: subq   %rsp, %rax
    0x1048cd680: andq   $-0xff9, %rax             ; imm = 0xF007 
    0x1048cd687: movq   %rax, (%rsi)
    0x1048cd68a: je     0x1048cd8f0
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
       rax = 0x000070000a259618
       rbx = 0x00000000000000c2
       rcx = 0x0000000747bb8798
       rdx = 0x000070000a259628
       rdi = 0x000000010100f220
       rsi = 0x000070000a259608
       rbp = 0x000070000a259670
       rsp = 0x000070000a259608
        r8 = 0x0000000000000000
        r9 = 0x0000000000000020
       r10 = 0x000000010430b270  libjvm.dylib`TemplateInterpreter::_active_table + 18432
       r11 = 0x00006fff09249400
       r12 = 0x0000000000000000
       r13 = 0x000000011c96ff98
       r14 = 0x000070000a2596a8
       r15 = 0x000000010100f220
       rip = 0x00000001048cd67d
    rflags = 0x0000000000000202
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 0x0000000000000000

(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x00000001048cd680
->  0x1048cd680: andq   $-0xff9, %rax             ; imm = 0xF007 
    0x1048cd687: movq   %rax, (%rsi)
    0x1048cd68a: je     0x1048cd8f0
    0x1048cd690: callq  0x1048cd69a
Target 0: (java) stopped.
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x00000001048cd687
->  0x1048cd687: movq   %rax, (%rsi)
    0x1048cd68a: je     0x1048cd8f0
    0x1048cd690: callq  0x1048cd69a
    0x1048cd695: jmp    0x1048cd8f0
Target 0: (java) stopped.
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x00000001048cd68a
->  0x1048cd68a: je     0x1048cd8f0
    0x1048cd690: callq  0x1048cd69a
    0x1048cd695: jmp    0x1048cd8f0
    0x1048cd69a: leaq   0x8(%rsp), %rax
Target 0: (java) stopped.
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x00000001048cd8f0
->  0x1048cd8f0: movq   %r13, -0x40(%rbp)
    0x1048cd8f4: movl   %eax, -0x16000(%rsp)
    0x1048cd8fb: movzbl (%r13), %ebx
    0x1048cd900: movabsq $0x10430b270, %r10        ; imm = 0x10430B270 
Target 0: (java) stopped.
(lldb) p ((oopDesc*)0x0000000747bb8798)->mark()->has_locker()
(bool) $3 = true
(lldb) p ((oopDesc*)0x0000000747bb8798)->mark()->locker()
(BasicLock *) $4 = 0x000070000a259618
(lldb) re r
General Purpose Registers:
       rax = 0x0000000000000000
       rbx = 0x00000000000000c2
       rcx = 0x0000000747bb8798
       rdx = 0x000070000a259628
       rdi = 0x000000010100f220
       rsi = 0x000070000a259608
       rbp = 0x000070000a259670
       rsp = 0x000070000a259608
        r8 = 0x0000000000000000
        r9 = 0x0000000000000020
       r10 = 0x000000010430b270  libjvm.dylib`TemplateInterpreter::_active_table + 18432
       r11 = 0x00006fff09249400
       r12 = 0x0000000000000000
       r13 = 0x000000011c96ff98
       r14 = 0x000070000a2596a8
       r15 = 0x000000010100f220
       rip = 0x00000001048cd8f0
    rflags = 0x0000000000000246
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 0x0000000000000000

(lldb) x 0x000070000a259608 -c 0x40
0x70000a259608: 00 00 00 00 00 00 00 00 98 87 bb 47 07 00 00 00  ..........?G....
0x70000a259618: 01 00 00 00 00 00 00 00 98 87 bb 47 07 00 00 00  ..........?G....
0x70000a259628: 08 96 25 0a 00 70 00 00 94 ff 96 1c 01 00 00 00  ..%..p...?......
0x70000a259638: a8 96 25 0a 00 70 00 00 88 00 97 1c 01 00 00 00  ?.%..p..........

相关汇编代码, 请参见 09 给对象添加偏向锁的调试 

这里在 monitorenter 的地方打了一个断点, 并且输出了 当前 lockObj 的相关信息之后, 直接 continue, 断点停在了 第二个 monitorenter 

我们可以整理一些结论 

1. 在第一个断点的时候, lockObj 没有锁, 就一个 0x001, 第二个断点的时候 已经加上了mian线程 获取了 lockObj 的轻量级锁 

2. 第二个断点相比于 第一个断点, [0x70000a259618 - 0x70000a259628) 增加了一个 BasicLockObject 关联 lockObj 对象 

 

然后 来到了第二个断点, 增加了一个 对应的 BasicLockObject 并更新了 BasicLockObject.obj 

来到这边变的业务处理, rax 初始化为1, 和 rcx(lockObj)进行了一个 or, 因为 rcx(lockObj) 现在 mark 记录的是 BasicLockObject 的地址(第一个断点的时候加的轻量级锁)(最后一个bit肯定为0), 所以 rax 现在为 &BasicLockObject + 1 

然后进行 cas(rsi, rcx, rax), 其中 rsi 存储的是这一次加锁的 BasicLockObject 的地址 

因为 rcx 对应的地址的数据 和 rax 不相同, 所以 cas 失败 

 

cas 操作失败之后, rax 为 rcx 的地址的值, 就是 第一次加锁的 BasicLockObject 的地址

然后来到后面, rax = rax - rsp 结果为 0x10 

然后 and 了一下 0b1111 0000 0000 0111, 之后 rax 为 0, goto done, 重入加锁成功 

rax 和 rsp 的 delta 可以再 0b0000 0000 0000 0000 - 0b0000 1111 1111 1000 这个范围内, 视为 轻量级锁的重入 

对了 还有一个细节, 这里如果是轻量级锁重入的场景的话 会设置 当前 BasicLockObject.lock.displaced_header 为 0[这里的rax一定为0]

 

为什么会挑这个 (zero_bits - os::vm_page_size()) = 7 - 4096 = -4089 ?, 呵呵 这里暂时还看不太明白, 我的理解应该是会和 线程栈帧的大小有关系呀  

 

 

轻量级锁的退出 

(lldb)  p _active_table._table[9][195]
(address) $1 = 0x000000010584f9e0 "XH;"
(lldb) b 0x000000010584f9e1
Breakpoint 5: address = 0x000000010584f9e1
(lldb) c
Process 1049 resuming
Process 1049 stopped
* thread #5, stop reason = breakpoint 5.1
    frame #0: 0x000000010584f9e1
->  0x10584f9e1: cmpq   (%rax), %rax
    0x10584f9e4: movq   -0x48(%rbp), %rsi
    0x10584f9e8: leaq   -0x48(%rbp), %rdx
    0x10584f9ec: jmp    0x10584f9fc
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
       rax = 0x0000000747bb8798
       rbx = 0x00000000000000c3
       rcx = 0x0000000747bb8798
       rdx = 0x0000700002548628
       rdi = 0x000000010500cc20
       rsi = 0x0000700002548608
       rbp = 0x0000700002548670
       rsp = 0x0000700002548608
        r8 = 0x0000000000000000
        r9 = 0x0000000000000020
       r10 = 0x0000000103b0aa70  libjvm.dylib`TemplateInterpreter::_active_table + 16384
       r11 = 0x0000000000000200
       r12 = 0x0000000000000000
       r13 = 0x000000011c7f1f99
       r14 = 0x00007000025486a8
       r15 = 0x000000010500cc20
       rip = 0x000000010584f9e1
    rflags = 0x0000000000000206
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 0x0000000000000000

(lldb) p ((oopDesc*)0x0000000747bb8798)->print()
com.hx.test04.Test26SynchronizeReentrantObject
{0x0000000747bb8798} - klass: 'com/hx/test04/Test26SynchronizeReentrantObject'
 - ---- fields (total size 5 words):
 - 'f01' 'I' @12  0
 - 'f02' 'I' @16  0
 - 'f03' 'I' @20  0
 - 'f04' 'I' @24  0
 - 'f05' 'I' @28  0
 - private 'identStr' 'Ljava/lang/String;' @32  "xyz"{0x0000000747bb87c0} (e8f770f8 0)
(lldb) p ((oopDesc*)0x0000000747bb8798)->mark()->has_locker()
(bool) $2 = true
(lldb) x 0x0000700002548608 -c 0x40
0x700002548608: 00 00 00 00 00 00 00 00 98 87 bb 47 07 00 00 00  ..........?G....
0x700002548618: 01 00 00 00 00 00 00 00 98 87 bb 47 07 00 00 00  ..........?G....
0x700002548628: 08 86 54 02 00 70 00 00 98 1f 7f 1c 01 00 00 00  ..T..p..........
0x700002548638: a8 86 54 02 00 70 00 00 88 20 7f 1c 01 00 00 00  ?.T..p... ......

// continue, 之后 断点停留在了 第二个 monitorexit
(lldb) c
Process 1049 resuming
Process 1049 stopped
* thread #5, stop reason = breakpoint 5.1
    frame #0: 0x000000010584f9e1
->  0x10584f9e1: cmpq   (%rax), %rax
    0x10584f9e4: movq   -0x48(%rbp), %rsi
    0x10584f9e8: leaq   -0x48(%rbp), %rdx
    0x10584f9ec: jmp    0x10584f9fc
Target 0: (java) stopped.
(lldb) p ((oopDesc*)0x0000000747bb8798)->mark()->has_locker()
(bool) $3 = true
(lldb) x 0x0000700002548608 -c 0x40
0x700002548608: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x700002548618: 01 00 00 00 00 00 00 00 98 87 bb 47 07 00 00 00  ..........?G....
0x700002548628: 08 86 54 02 00 70 00 00 99 1f 7f 1c 01 00 00 00  ..T..p..........
0x700002548638: a8 86 54 02 00 70 00 00 88 20 7f 1c 01 00 00 00  ?.T..p... ......
(lldb) b 0x10584fcdd
Breakpoint 6: address = 0x000000010584fcdd
(lldb) c
Process 1049 resuming
Process 1049 stopped
* thread #5, stop reason = breakpoint 6.1
    frame #0: 0x000000010584fcdd
->  0x10584fcdd: leaq   (%rsi), %rax
    0x10584fce0: movq   0x8(%rsi), %rcx
    0x10584fce4: movq   $0x0, 0x8(%rsi)
    0x10584fcec: movq   (%rax), %rdx
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
       rax = 0x0000000747bb8798
       rbx = 0x00000000000000c3
       rcx = 0x000000011c7f2000
       rdx = 0x0000700002548628
       rdi = 0x000000010500cc20
       rsi = 0x0000700002548618
       rbp = 0x0000700002548670
       rsp = 0x0000700002548600
        r8 = 0x0000000000000000
        r9 = 0x0000000000000020
       r10 = 0x0000000103b0aa70  libjvm.dylib`TemplateInterpreter::_active_table + 16384
       r11 = 0x0000000000000200
       r12 = 0x0000000000000000
       r13 = 0x000000011c7f1fa5
       r14 = 0x00007000025486a8
       r15 = 0x000000010500cc20
       rip = 0x000000010584fcdd
    rflags = 0x0000000000000246
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 0x0000000000000000

(lldb) stepi
Process 1049 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010584fce0
->  0x10584fce0: movq   0x8(%rsi), %rcx
    0x10584fce4: movq   $0x0, 0x8(%rsi)
    0x10584fcec: movq   (%rax), %rdx
    0x10584fcef: testq  %rdx, %rdx
Target 0: (java) stopped.
(lldb) stepi
Process 1049 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010584fce4
->  0x10584fce4: movq   $0x0, 0x8(%rsi)
    0x10584fcec: movq   (%rax), %rdx
    0x10584fcef: testq  %rdx, %rdx
    0x10584fcf2: je     0x10584ff67
Target 0: (java) stopped.
(lldb) stepi
Process 1049 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010584fcec
->  0x10584fcec: movq   (%rax), %rdx
    0x10584fcef: testq  %rdx, %rdx
    0x10584fcf2: je     0x10584ff67
    0x10584fcf8: lock
Target 0: (java) stopped.
(lldb) stepi
Process 1049 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010584fcef
->  0x10584fcef: testq  %rdx, %rdx
    0x10584fcf2: je     0x10584ff67
    0x10584fcf8: lock
    0x10584fcf9: cmpxchgq %rdx, (%rcx)
Target 0: (java) stopped.
(lldb) stepi
Process 1049 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010584fcf2
->  0x10584fcf2: je     0x10584ff67
    0x10584fcf8: lock
    0x10584fcf9: cmpxchgq %rdx, (%rcx)
    0x10584fcfd: je     0x10584ff67
Target 0: (java) stopped.
(lldb) stepi
Process 1049 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010584fcf8
->  0x10584fcf8: lock
    0x10584fcf9: cmpxchgq %rdx, (%rcx)
    0x10584fcfd: je     0x10584ff67
    0x10584fd03: movq   %rcx, 0x8(%rsi)
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
       rax = 0x0000700002548618
       rbx = 0x00000000000000c3
       rcx = 0x0000000747bb8798
       rdx = 0x0000000000000001
       rdi = 0x000000010500cc20
       rsi = 0x0000700002548618
       rbp = 0x0000700002548670
       rsp = 0x0000700002548600
        r8 = 0x0000000000000000
        r9 = 0x0000000000000020
       r10 = 0x0000000103b0aa70  libjvm.dylib`TemplateInterpreter::_active_table + 16384
       r11 = 0x0000000000000200
       r12 = 0x0000000000000000
       r13 = 0x000000011c7f1fa5
       r14 = 0x00007000025486a8
       r15 = 0x000000010500cc20
       rip = 0x000000010584fcf8
    rflags = 0x0000000000000202
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 0x0000000000000000

(lldb) stepi
Process 1049 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010584fcfd
->  0x10584fcfd: je     0x10584ff67
    0x10584fd03: movq   %rcx, 0x8(%rsi)
    0x10584fd07: callq  0x10584fd11
    0x10584fd0c: jmp    0x10584ff67
Target 0: (java) stopped.
(lldb) stepi
Process 1049 stopped
* thread #5, stop reason = instruction step into
    frame #0: 0x000000010584ff67
->  0x10584ff67: movq   -0x40(%rbp), %r13
    0x10584ff6b: popq   %rax
    0x10584ff6c: movzbl 0x1(%r13), %ebx
    0x10584ff71: incq   %r13
Target 0: (java) stopped.
(lldb) p ((oopDesc*)0x0000000747bb8798)->mark()->has_locker()
(bool) $4 = false
(lldb) x  0x0000700002548600 -c 0x40
0x700002548600: 98 87 bb 47 07 00 00 00 00 00 00 00 00 00 00 00  ..?G............
0x700002548610: 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00  ................
0x700002548620: 00 00 00 00 00 00 00 00 08 86 54 02 00 70 00 00  ..........T..p..
0x700002548630: a5 1f 7f 1c 01 00 00 00 a8 86 54 02 00 70 00 00  ?.......?.T..p..

断点来到第一个 monitorexit 的时候, 此时 lockObj 的轻量级锁被 main 持有, 并且 main 重入了一次 

查看一下 栈顶的信息, 和 main 重入获取 lockObj 的结果一致, 第一个 BasicLockObject.lock.displaced_header 存放的是 lockObj之前的结果, 第二个 BasicLockObject.lock.displaced_header 里面存放的是 0 

 

然后 continue, 到达第二个 monitorexit  

第一个 monitorexit 因为对应的是 重入的 monitorenter, 因此 没有做太多的事情, 仅仅是单纯的吧 第二个 BasicLockObject.obj 置空了 

然后 到达 第二个 monitorexit 业务处理之后, 吧 第一个 BasicLockObject.obj 置空了, 并且吧 第一个 BasicLockObject.lock.displaced_header cas 替换到了 lockObj 的对象头里面 

然后这个时候 再来查看 lockObj 的轻量级锁的相关信息, 就已经没有被 main 线程持有了 

查看栈的内存信息, 可以发现 两个 BasicLockObject.obj 都已经被置空了 

 

 

轻量级锁线程同步块执行完成 其他线程尝试加锁

package com.hx.test04;

/**
 * Test27MultiThreadInBiasLock
 *
 * @author Jerry.X.He <970655147@qq.com>
 * @version 1.0
 * @date 2020-04-03 15:14
 */
public class Test27MultiThreadInBiasLock implements Cloneable {

  // identStr
  private String identStr = "xyz";
  int f01;
  int f02;
  int f03;
  int f04;
  int f05;

  // Test25SynchronizeObject
  public static void main(String[] args) throws Exception {

    Test27MultiThreadInBiasLock lockObj = new Test27MultiThreadInBiasLock();

    doClone(lockObj);
    synchronized (lockObj) {

    }

    new Thread() {
      @Override
      public void run() {
        doClone(lockObj);
        synchronized (lockObj) {

        }
      }
    }.start();

    Test25SynchronizeObject.sleep(2000);
  }

  // doClone
  private static void doClone(Test27MultiThreadInBiasLock obj) {
    try {
      obj.clone();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}

 

调试信息如下 

(lldb) br set -f jvm.cpp -l 627 -c ((obj()->klass()->is_instance_klass())&&(((InstanceKlass*)obj()->klass())->java_fields_count()==6))
Breakpoint 3: where = libjvm.dylib`::JVM_Clone(JNIEnv *, jobject) + 516 at jvm.cpp:627:28, address = 0x0000000103171ab4
(lldb) p _active_table._table[9][194]
(address) $0 = 0x000000010504f600 "XH;"
(lldb) c
Process 1619 resuming
Process 1619 stopped
* thread #5, stop reason = breakpoint 3.1
    frame #0: 0x0000000103171ab4 libjvm.dylib`::JVM_Clone(env=0x0000000100808648, handle=0x000070000deca5c8) at jvm.cpp:627:28
   624 	JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
   625 	  JVMWrapper("JVM_Clone");
   626 	  Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
-> 627 	  const KlassHandle klass (THREAD, obj->klass());
   628 	  JvmtiVMObjectAllocEventCollector oam;
   629 	
   630 	#ifdef ASSERT
Target 0: (java) stopped.

(lldb) c
Process 1619 resuming
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = breakpoint 3.1
    frame #0: 0x0000000103171ab4 libjvm.dylib`::JVM_Clone(env=0x0000000114851848, handle=0x000070001002d5e0) at jvm.cpp:627:28
   624 	JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
   625 	  JVMWrapper("JVM_Clone");
   626 	  Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
-> 627 	  const KlassHandle klass (THREAD, obj->klass());
   628 	  JvmtiVMObjectAllocEventCollector oam;
   629 	
   630 	#ifdef ASSERT
Target 0: (java) stopped.

(lldb) b 0x000000010504f600
Breakpoint 4: address = 0x000000010504f600

// continue 之后进入 Thread-0 的 monitorenter 
(lldb) c
Process 1619 resuming
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = breakpoint 4.1
    frame #0: 0x000000010504f600
->  0x10504f600: popq   %rax
    0x10504f601: cmpq   (%rax), %rax
    0x10504f604: xorl   %esi, %esi
    0x10504f606: movq   -0x48(%rbp), %rcx
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
       rax = 0x0000000747bb8f68
       rbx = 0x00000000000000c2
       rcx = 0x00000000000000cb
       rdx = 0x0000000000000000
       rdi = 0x000000010500b220
       rsi = 0x000070001002d650
       rbp = 0x000070001002d6f8
       rsp = 0x000070001002d6a8
        r8 = 0x0000000000000001
        r9 = 0x0000000747bf9cb8
       r10 = 0x0000000103b0b270  libjvm.dylib`TemplateInterpreter::_active_table + 18432
       r11 = 0x000070001002d5e0
       r12 = 0x0000000000000000
       r13 = 0x000000011c75e845
       r14 = 0x000070001002d718
       r15 = 0x0000000114851620
       rip = 0x000000010504f600
    rflags = 0x0000000000000202
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 0x0000000000000000

(lldb) p ((oopDesc*)0x0000000747bb8f68)->print()
com.hx.test04.Test27MultiThreadInBiasLock 
{0x0000000747bb8f68} - klass: 'com/hx/test04/Test27MultiThreadInBiasLock'
 - ---- fields (total size 5 words):
 - 'f01' 'I' @12  0
 - 'f02' 'I' @16  0
 - 'f03' 'I' @20  0
 - 'f04' 'I' @24  0
 - 'f05' 'I' @28  0
 - private 'identStr' 'Ljava/lang/String;' @32  "xyz"{0x0000000747bb8f90} (e8f771f2 0)
(lldb) p ((oopDesc*)0x0000000747bb8f68)->mark()->has_locker()
(bool) $3 = false
(lldb) b 0x10504f663 
Breakpoint 5: address = 0x000000010504f663
(lldb) c
Process 1619 resuming
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = breakpoint 5.1
    frame #0: 0x000000010504f663
->  0x10504f663: movq   0x8(%rsi), %rcx
    0x10504f667: movl   $0x1, %eax
    0x10504f66c: orq    (%rcx), %rax
    0x10504f66f: movq   %rax, (%rsi)
Target 0: (java) stopped.
(lldb) stepi
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = instruction step into
    frame #0: 0x000000010504f667
->  0x10504f667: movl   $0x1, %eax
    0x10504f66c: orq    (%rcx), %rax
    0x10504f66f: movq   %rax, (%rsi)
    0x10504f672: lock   
Target 0: (java) stopped.
(lldb) stepi
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = instruction step into
    frame #0: 0x000000010504f66c
->  0x10504f66c: orq    (%rcx), %rax
    0x10504f66f: movq   %rax, (%rsi)
    0x10504f672: lock   
    0x10504f673: cmpxchgq %rsi, (%rcx)
Target 0: (java) stopped.
(lldb) stepi
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = instruction step into
    frame #0: 0x000000010504f66f
->  0x10504f66f: movq   %rax, (%rsi)
    0x10504f672: lock   
    0x10504f673: cmpxchgq %rsi, (%rcx)
    0x10504f677: je     0x10504f8f0
Target 0: (java) stopped.
(lldb) stepi
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = instruction step into
    frame #0: 0x000000010504f672
->  0x10504f672: lock   
    0x10504f673: cmpxchgq %rsi, (%rcx)
    0x10504f677: je     0x10504f8f0
    0x10504f67d: subq   %rsp, %rax
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
       rax = 0x0000000000000001
       rbx = 0x00000000000000c2
       rcx = 0x0000000747bb8f68
       rdx = 0x000070001002d6b0
       rdi = 0x000000010500b220
       rsi = 0x000070001002d6a0
       rbp = 0x000070001002d6f8
       rsp = 0x000070001002d6a0
        r8 = 0x0000000000000001
        r9 = 0x0000000747bf9cb8
       r10 = 0x0000000103b0b270  libjvm.dylib`TemplateInterpreter::_active_table + 18432
       r11 = 0x000070001002d5e0
       r12 = 0x0000000000000000
       r13 = 0x000000011c75e846
       r14 = 0x000070001002d718
       r15 = 0x0000000114851620
       rip = 0x000000010504f672
    rflags = 0x0000000000000202
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 0x0000000000000000

(lldb) x 0x0000000747bb8f68
0x747bb8f68: 01 00 00 00 00 00 00 00 86 1f 01 f8 00 00 00 00  ...........?....
0x747bb8f78: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
(lldb) stepi
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = instruction step into
    frame #0: 0x000000010504f677
->  0x10504f677: je     0x10504f8f0
    0x10504f67d: subq   %rsp, %rax
    0x10504f680: andq   $-0xff9, %rax             ; imm = 0xF007 
    0x10504f687: movq   %rax, (%rsi)
Target 0: (java) stopped.
(lldb) stepi
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = instruction step into
    frame #0: 0x000000010504f8f0
->  0x10504f8f0: movq   %r13, -0x40(%rbp)
    0x10504f8f4: movl   %eax, -0x16000(%rsp)
    0x10504f8fb: movzbl (%r13), %ebx
    0x10504f900: movabsq $0x103b0b270, %r10        ; imm = 0x103B0B270 
Target 0: (java) stopped.

可以看到 continue 之后, Thread-0 来获取 lockObj 的锁的时候 

lockObj 上面的轻量级锁已经被 main线程 释放了, 并且 对象头也替换成了 加锁之前的对象头了 

然后所以这里的 Thread-0 获取锁 相当于又是走的一次 获取 lockObj 的轻量级锁的过程, 并且加锁成功 

 

 

完 

 

 

参考

09 给对象添加偏向锁的调试

10 偏向锁的退出的调试

11 偏向锁的重入 以及 线程1获取偏向锁并释放线程2获取锁 的调试

12 给对象添加轻量级锁的调试

 

点赞收藏
分类:标签:
黄金键盘
请先登录,查看1条精彩评论吧
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

随机一门技术分享之Netty

随机一门技术分享之Netty

从 Linux 内核角度探秘 JDK MappedByteBuffer

从 Linux 内核角度探秘 JDK MappedByteBuffer

MappedByteBuffer VS FileChannel:从内核层面对比两者的性能差异

MappedByteBuffer VS FileChannel:从内核层面对比两者的性能差异

2
1