簡體   English   中英

在運行時了解同步方法,沒有爭用

[英]Understanding synchronized method at runtime with no contention

java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)

這一切都是出於學習目的,而不是用於生產。

我試圖了解JVM HotSpot上運行時的synchronized行為。 這是我嘗試過的:

public class App {
    public static int i = 0;

    public static void main(String[] args) {
        for(int i = 0; i < 10000; i++){
            increment();
        }
        if(new Object().hashCode() != i){
            System.out.print("");
        }
    }

    static synchronized void increment(){
        i++;
    }
}

這是整個應用程序。 我有興趣了解它如何在運行時工作。 所以我用java -server -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*App.increment -jar target/test-1.0.0.jar反匯編java -server -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*App.increment -jar target/test-1.0.0.jar得到了這個:

  # {method} {0x00007f62e5693438} 'increment' '()V' in 'com/test/App'
  #           [sp+0x50]  (sp of caller)
  0x00007f62d1112880: mov     %eax,0xfffffffffffec000(%rsp)
  0x00007f62d1112887: push    %rbp
  0x00007f62d1112888: sub     $0x40,%rsp
  0x00007f62d111288c: movabs  $0xd6f77a00,%rsi  ;   {oop(a 'java/lang/Class' = 'com/test/App')}
  0x00007f62d1112896: lea     0x20(%rsp),%rdi
  0x00007f62d111289b: mov     %rsi,0x8(%rdi)
  0x00007f62d111289f: mov     (%rsi),%rax
  0x00007f62d11128a2: mov     %rax,%rbx
  0x00007f62d11128a5: and     $0x7,%rbx
  0x00007f62d11128a9: cmp     $0x5,%rbx
  0x00007f62d11128ad: jne     0x7f62d1112934
  0x00007f62d11128b3: mov     0x8(%rsi),%ebx
  0x00007f62d11128b6: shl     $0x3,%rbx
  0x00007f62d11128ba: mov     0xa8(%rbx),%rbx
  0x00007f62d11128c1: or      %r15,%rbx
  0x00007f62d11128c4: xor     %rax,%rbx
  0x00007f62d11128c7: and     $0xffffffffffffff87,%rbx
  0x00007f62d11128cb: je      0x7f62d111295c
  0x00007f62d11128d1: test    $0x7,%rbx
  0x00007f62d11128d8: jne     0x7f62d1112921
  0x00007f62d11128da: test    $0x300,%rbx
  0x00007f62d11128e1: jne     0x7f62d1112900
  0x00007f62d11128e3: and     $0x37f,%rax
  0x00007f62d11128ea: mov     %rax,%rbx
  0x00007f62d11128ed: or      %r15,%rbx
  0x00007f62d11128f0: lock cmpxchg %rbx,(%rsi)
  0x00007f62d11128f5: jne     0x7f62d11129dd
  0x00007f62d11128fb: jmpq    0x7f62d111295c
  0x00007f62d1112900: mov     0x8(%rsi),%ebx
  0x00007f62d1112903: shl     $0x3,%rbx
  0x00007f62d1112907: mov     0xa8(%rbx),%rbx
  0x00007f62d111290e: or      %r15,%rbx
  0x00007f62d1112911: lock cmpxchg %rbx,(%rsi)
  0x00007f62d1112916: jne     0x7f62d11129dd
  0x00007f62d111291c: jmpq    0x7f62d111295c
  0x00007f62d1112921: mov     0x8(%rsi),%ebx
  0x00007f62d1112924: shl     $0x3,%rbx
  0x00007f62d1112928: mov     0xa8(%rbx),%rbx
  0x00007f62d111292f: lock cmpxchg %rbx,(%rsi)
  0x00007f62d1112934: mov     (%rsi),%rax
  0x00007f62d1112937: or      $0x1,%rax
  0x00007f62d111293b: mov     %rax,(%rdi)
  0x00007f62d111293e: lock cmpxchg %rdi,(%rsi)
  0x00007f62d1112943: je      0x7f62d111295c
  0x00007f62d1112949: sub     %rsp,%rax
  0x00007f62d111294c: and     $0xfffffffffffff007,%rax
  0x00007f62d1112953: mov     %rax,(%rdi)
  0x00007f62d1112956: jne     0x7f62d11129dd
  0x00007f62d111295c: movabs  $0x7f62e5693668,%rax  ;   {metadata(method data for {method} {0x00007f62e5693438} 'increment' '()V' in 'com/test/App')}
  0x00007f62d1112966: mov     0xdc(%rax),%esi
  0x00007f62d111296c: add     $0x8,%esi
  0x00007f62d111296f: mov     %esi,0xdc(%rax)
  0x00007f62d1112975: movabs  $0x7f62e5693438,%rax  ;   {metadata({method} {0x00007f62e5693438} 'increment' '()V' in 'com/test/App')}
  0x00007f62d111297f: and     $0x1ff8,%esi
  0x00007f62d1112985: cmp     $0x0,%esi
  0x00007f62d1112988: je      0x7f62d11129f0
  0x00007f62d111298e: movabs  $0xd6f77a00,%rax  ;   {oop(a 'java/lang/Class' = 'com/test/App')}
  0x00007f62d1112998: mov     0x68(%rax),%esi   ;*getstatic i
                                                ; - com.test.App::increment@0 (line 19)

  0x00007f62d111299b: incl    %esi
  0x00007f62d111299d: mov     %esi,0x68(%rax)   ;*putstatic i
                                                ; - com.test.App::increment@5 (line 19)

  0x00007f62d11129a0: lea     0x20(%rsp),%rax
  0x00007f62d11129a5: mov     0x8(%rax),%rdi
  0x00007f62d11129a9: mov     (%rdi),%rsi
  0x00007f62d11129ac: and     $0x7,%rsi
  0x00007f62d11129b0: cmp     $0x5,%rsi
  0x00007f62d11129b4: je      0x7f62d11129d1
  0x00007f62d11129ba: mov     (%rax),%rsi
  0x00007f62d11129bd: test    %rsi,%rsi
  0x00007f62d11129c0: je      0x7f62d11129d1
  0x00007f62d11129c6: lock cmpxchg %rsi,(%rdi)
  0x00007f62d11129cb: jne     0x7f62d1112a04    ;*return
                                                ; - com.test.App::increment@8 (line 20)

  0x00007f62d11129d1: add     $0x40,%rsp
  0x00007f62d11129d5: pop     %rbp
  0x00007f62d11129d6: test    %eax,0x18b4c724(%rip)  ;   {poll_return}
  0x00007f62d11129dc: retq
  0x00007f62d11129dd: mov     %rsi,0x8(%rsp)
  0x00007f62d11129e2: mov     %rdi,(%rsp)
  0x00007f62d11129e6: callq   0x7f62d1105420    ; OopMap{rsi=Oop [40]=Oop off=363}
                                                ;*synchronization entry
                                                ; - com.test.App::increment@-1 (line 19)
                                                ;   {runtime_call}
  0x00007f62d11129eb: jmpq    0x7f62d111295c
  0x00007f62d11129f0: mov     %rax,0x8(%rsp)
  0x00007f62d11129f5: movq    $0xffffffffffffffff,(%rsp)
  0x00007f62d11129fd: callq   0x7f62d1106fa0    ; OopMap{[40]=Oop off=386}
                                                ;*synchronization entry
                                                ; - com.test.App::increment@-1 (line 19)
                                                ;   {runtime_call}
  0x00007f62d1112a02: jmp     0x7f62d111298e
  0x00007f62d1112a04: lea     0x20(%rsp),%rax
  0x00007f62d1112a09: mov     %rax,(%rsp)
  0x00007f62d1112a0d: callq   0x7f62d11057e0    ;   {runtime_call}
  0x00007f62d1112a12: jmp     0x7f62d11129d1
  0x00007f62d1112a14: nop
  0x00007f62d1112a15: nop
  0x00007f62d1112a16: mov     0x2a8(%r15),%rax
  0x00007f62d1112a1d: movabs  $0x0,%r10
  0x00007f62d1112a27: mov     %r10,0x2a8(%r15)
  0x00007f62d1112a2e: movabs  $0x0,%r10
  0x00007f62d1112a38: mov     %r10,0x2b0(%r15)
  0x00007f62d1112a3f: mov     %rax,%rbx
  0x00007f62d1112a42: lea     0x20(%rsp),%rax
  0x00007f62d1112a47: mov     0x8(%rax),%rsi
  0x00007f62d1112a4b: mov     (%rsi),%rdi
  0x00007f62d1112a4e: and     $0x7,%rdi
  0x00007f62d1112a52: cmp     $0x5,%rdi
  0x00007f62d1112a56: je      0x7f62d1112a73
  0x00007f62d1112a5c: mov     (%rax),%rdi
  0x00007f62d1112a5f: test    %rdi,%rdi
  0x00007f62d1112a62: je      0x7f62d1112a73
  0x00007f62d1112a68: lock cmpxchg %rdi,(%rsi)
  0x00007f62d1112a6d: jne     0x7f62d1112a80
  0x00007f62d1112a73: mov     %rbx,%rax
  0x00007f62d1112a76: add     $0x40,%rsp
  0x00007f62d1112a7a: pop     %rbp
  0x00007f62d1112a7b: jmpq    0x7f62d10755a0    ;   {runtime_call}
  0x00007f62d1112a80: lea     0x20(%rsp),%rax
  0x00007f62d1112a85: mov     %rax,(%rsp)
  0x00007f62d1112a89: callq   0x7f62d11057e0    ;   {runtime_call}
  0x00007f62d1112a8e: jmp     0x7f62d1112a73
  0x00007f62d1112a90: hlt
  0x00007f62d1112a91: hlt
  0x00007f62d1112a92: hlt
  0x00007f62d1112a93: hlt
  0x00007f62d1112a94: hlt
  0x00007f62d1112a95: hlt
  0x00007f62d1112a96: hlt
  0x00007f62d1112a97: hlt
  0x00007f62d1112a98: hlt
  0x00007f62d1112a99: hlt
  0x00007f62d1112a9a: hlt
  0x00007f62d1112a9b: hlt
  0x00007f62d1112a9c: hlt
  0x00007f62d1112a9d: hlt
  0x00007f62d1112a9e: hlt
  0x00007f62d1112a9f: hlt

我被困惑的是這個片段:

  0x00007f62d11128f0: lock cmpxchg %rbx,(%rsi)   ;1st cmpxchg
  0x00007f62d11128f5: jne     0x7f62d11129dd
  0x00007f62d11128fb: jmpq    0x7f62d111295c
  0x00007f62d1112900: mov     0x8(%rsi),%ebx
  0x00007f62d1112903: shl     $0x3,%rbx
  0x00007f62d1112907: mov     0xa8(%rbx),%rbx
  0x00007f62d111290e: or      %r15,%rbx
  0x00007f62d1112911: lock cmpxchg %rbx,(%rsi)   ;2nd cmpxchg
  0x00007f62d1112916: jne     0x7f62d11129dd
  0x00007f62d111291c: jmpq    0x7f62d111295c
  0x00007f62d1112921: mov     0x8(%rsi),%ebx
  0x00007f62d1112924: shl     $0x3,%rbx
  0x00007f62d1112928: mov     0xa8(%rbx),%rbx
  0x00007f62d111292f: lock cmpxchg %rbx,(%rsi)   ;3rd cmpxchg
  0x00007f62d1112934: mov     (%rsi),%rax
  0x00007f62d1112937: or      $0x1,%rax
  0x00007f62d111293b: mov     %rax,(%rdi) 
  0x00007f62d111293e: lock cmpxchg %rdi,(%rsi)   ;4th cmpxchg
  0x00007f62d1112943: je      0x7f62d111295c
  0x00007f62d1112949: sub     %rsp,%rax
  0x00007f62d111294c: and     $0xfffffffffffff007,%rax
  0x00007f62d1112953: mov     %rax,(%rdi)
  0x00007f62d1112956: jne     0x7f62d11129dd

首先,我們將rbx[rsi]進行比較和交換。 由於lock cmpxchng修改了ZF,我們有條件地跳轉到jne 0x7f62d11129dd (我認為這是在CAS失敗的情況下)。 如果CAS成功,我們無條件地跳轉到jmpq 0x7f62d111295c

題:

為什么我們有4個lock cmpxchg %rbx, ($rsi)如果我們在第一次lock cmpxchg %rbx, ($rsi)之后的跳轉中跳過它們?

UPD :我想我理解為什么我們需要這種跳躍。 先沒有注意到這些說明:

0x00007f62d11128d1: test    $0x7,%rbx
0x00007f62d11128d8: jne     0x7f62d1112921
0x00007f62d11128da: test    $0x300,%rbx
0x00007f62d11128e1: jne     0x7f62d1112900

事情還不太清楚當時rbx包含的內容。 我一開始就看着。 這里是:

0x00007f62d111288c: movabs  $0xd6f77a00,%rsi  ; seems the object data
;...
0x00007f62d111289b: mov     %rsi,0x8(%rdi) ; Header offset?
0x00007f62d111289f: mov     (%rsi),%rax
0x00007f62d11128a2: mov     %rax,%rbx
0x00007f62d11128a5: and     $0x7,%rbx ; Why do we do this and?
  1. 您正在查看C1編譯的方法。 這不是通常在熱路徑上運行的。 一旦使用C2編譯main方法,就不會調用increment方法,而是將其內聯到外部循環中。
  2. 您要問的一段代碼是偏向鎖輸入序列。 為了更好地理解它,您需要知道偏置鎖定的工作原理 這里的rbx包含對象標題(標記字)。 and $0x7, rbx指令掩蓋偏置的鎖模式位。
  3. 查看MacroAssembler::biased_locking_enter的源代碼,看看發生了什么。 順便說一句,這些消息來源附有許多有價值的評論,這些評論確實有助於理解算法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM