91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java 鎖粗化與循環問題

發布時間:2020-09-05 01:31:17 來源:腳本之家 閱讀:122 作者:唐尤華 欄目:編程語言

1. 寫在前面

“JVM 解剖公園”是一個持續更新的系列迷你博客,閱讀每篇文章一般需要5到10分鐘。限于篇幅,僅對某個主題按照問題、測試、基準程序、觀察結果深入講解。因此,這里的數據和討論可以當軼事看,并沒有做一致性、寫作風格、句法和語義錯誤、重復或一致性檢查。如果選擇采信文中內容,風險自負。

Aleksey Shipilёv,JVM 性能極客

推特 @shipilev

問題、評論、建議發送到 aleksey@shipilev.net

譯注:鎖粗化(Lock Coarsening)。鎖粗化是合并使用相同鎖對象的相鄰同步塊的過程。如果編譯器不能使用鎖省略(Lock Elision)消除鎖,那么可以使用鎖粗化來減少開銷。

2. 問題

眾所周知,Hotspot 確實進行了鎖粗化優化,可以有效合并幾個相鄰同步塊,從而降低鎖開銷。能夠把下面的代碼

synchronized (obj) {
 // 語句 1
}
synchronized (obj) {
 // 語句 2
}

轉化為

synchronized (obj) {
 // 語句 1
 // 語句 2
}

問題來了,Hotspot 能否對循環進行這種優化?例如,把

for (...) {
 synchronized (obj) {
  // 一些操作
 }
}

優化成下面這樣?

synchronized (this) {
 for (...) {
   // 一些操作
 }
}

理論上,沒有什么能阻止我們這樣做,甚至可以把這種優化看作只針對鎖的優化,像 loop unswitching 一樣。然而,缺點是可能把鎖優化后變得過粗,線程在執行循環時會占據所有的鎖。

譯注:Loop unswitching 是一種編譯器優化技術。通過復制循環主體,在 if 和 else 語句中放一份循環體代碼,實現將條件句的內部循環移到循環外部,進而提高循環的并行性。由于處理器可以快速運算矢量,因此執行速度得到提升。

3. 實驗

要回答這個問題,最簡單的辦法就是找到 Hotspot 優化的證據。幸運的是,有了 JMH 幫助這項工作變得非常簡單。JMH 不僅在構建基準測試時有用,并且在分析基準測試方面同樣好用。讓我們從一個簡單的基準測試開始:

@Fork(..., jvmArgsPrepend = {"-XX:-UseBiasedLocking"})
@State(Scope.Benchmark)
public class LockRoach {
  int x;
  @Benchmark
  @CompilerControl(CompilerControl.Mode.DONT_INLINE)
  public void test() {
    for (int c = 0; c < 1000; c++) {
      synchronized (this) {
        x += 0x42;
      }
    }
  }
}

(完整的源代碼參見這里 ,請查看原文鏈接)

這里有一些重要的技巧:

使用 -XX:-UseBiasedLocking 禁用偏向鎖(Biased Lock)可以避免啟動時間過長。由于偏向鎖不會立即啟動,在初始化階段要等待5秒鐘(參見 BiasedLockingStartupDelay 選項)
禁用 @Benchmark 方法內聯操作可以幫助我們從反匯編中分離相關內容
加上“魔數” 0x42 有助于快速從反匯編中定位加法操作

譯注:偏向鎖(Biased Locking)。盡管 CAS 原子指令相對于重量級鎖來說開銷比較小,但還是存在非常可觀的本地延遲,為了在無鎖競爭的情況下避免取鎖獲過程中執行不必要的 CAS 原子指令提出了偏向鎖技術。
論文 Quickly Reacquirable Locks ,作者 Dave Dice、Mark Moir、William Scherer III。

運行環境 i7 4790K、Linux x86_64、JDK EA 9b156:

Benchmark            Mode  Cnt      Score    Error  Units
LockRoach.test       avgt    5   5331.617 ± 19.051  ns/op

從上面運行數據能分析出什么結果?什么都看不出來,對吧?我們需要調查背后到底發生了什么。這時 -prof perfasm 配置可以派上用場,它能顯示生成代碼中的熱點區域。用默認設置運行,能夠發現最熱的指令是加鎖 lock cmpxchg(CAS),而且只打印指令附近的代碼。-prof perfasm:mergeMargin=1000 配置可以將這些熱點區域合并保存為輸出片段,乍看之下可能覺得有點恐怖。

進一步分析得出連續的跳轉指令是鎖定或解鎖,注意循環次數最多的代碼(第一列),可以看到最熱的循環像下面這樣:

↗ 0x00007f455cc708c1: lea  0x20(%rsp),%rbx
 │     < 省略若干代碼,進入 monitor >   ; <--- coarsened(粗化)!
 │ 0x00007f455cc70918: mov  (%rsp),%r10    ; 加載 $this
 │ 0x00007f455cc7091c: mov  0xc(%r10),%r11d  ; 加載 $this.x
 │ 0x00007f455cc70920: mov  %r11d,%r10d    ; ...hm...
 │ 0x00007f455cc70923: add  $0x42,%r10d    ; ...hmmm...
 │ 0x00007f455cc70927: mov  (%rsp),%r8     ; ...hmmmmm!...
 │ 0x00007f455cc7092b: mov  %r10d,0xc(%r8)   ; LOL Hotspot,冗余存儲,下面省略兩行
 │ 0x00007f455cc7092f: add  $0x108,%r11d    ; 加 0x108 = 0x42 * 4 <-- 展開4次
 │ 0x00007f455cc70936: mov  %r11d,0xc(%r8)   ; 把 $this.x 回省略若干代碼,退出 monitor >   ; <--- coarsened(粗化)!
 │ 0x00007f455cc709c6: add  $0x4,%ebp     ; c += 4  <--- 展開4次
 │ 0x00007f455cc709c9: cmp  $0x3e5,%ebp    ; c < 1000?
 ╰ 0x00007f455cc709cf: jl   0x00007f455cc708c1

哈哈。循環似乎被展開了4次,然后這4個迭代中實現鎖粗化!為了排除循環展開對鎖粗化的影響,我們可以通過-XX:LoopUnrollLimit=1 配置裁剪循環展開,再次量化受限后的粗化性能。

譯注:Loop unrolling(循環展開),也稱 Loop unwinding,是一種循環轉換技術。它試圖以犧牲二進制大小為代價優化程序的執行速度,這種方法被稱為時空折衷。轉換可以由程序員手動執行,也可以由編譯器優化。

Benchmark      Mode Cnt   Score  Error Units
# Default
LockRoach.test    avgt  5  5331.617 ± 19.051 ns/op
# -XX:LoopUnrollLimit=1
LockRoach.test    avgt  5 20679.043 ± 3.133 ns/op

哇,性能提升了4倍!顯而易見的,因為我們已經觀察到最熱的指令是加鎖 lock cmpxchg。當然,4倍后的粗化鎖意味著4倍吞吐量。非常酷,我們是不是可以宣布成功,然后繼續前進?還沒有。我們必須驗證禁用循環展開真正提供了我們想要進行比較的內容。perfasm 的結果似乎表明它含有類似的熱點循環,只是跨了一大步。

↗ 0x00007f964d0893d2: lea  0x20(%rsp),%rbx
 │     < 省略若干代碼,進入 monitor >
 │ 0x00007f964d089429: mov  (%rsp),%r10    ; 加載 $this
 │ 0x00007f964d08942d: addl  $0x42,0xc(%r10)  ; $this.x += 0x42
 │     < 省略若干代碼,退出 monitor >
 │ 0x00007f964d0894be: inc  %ebp        ; c++
 │ 0x00007f964d0894c0: cmp  $0x3e8,%ebp    ; c < 1000?
 ╰ 0x00007f964d0894c6: jl   0x00007f964d0893d2 ;

一切都檢查 OK。

4. 觀察結果

當鎖粗化在整個循環中不起作用時,一旦中間看起來好像存在 N 個相鄰的加鎖解鎖操作,另一種循環優化——循環展開會提供常規鎖粗化。這將提高性能,并有助于限制粗化的范圍,以避免長循環過度粗化。

總結

以上所述是小編給大家介紹的Java 鎖粗化與循環問題,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對億速云網站的支持!

如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

思南县| 武安市| 郴州市| 广东省| 仁布县| 五莲县| 顺义区| 北碚区| 象山县| 峨边| 当阳市| 东至县| 临猗县| 保康县| 玛纳斯县| 凌海市| 中牟县| 屯昌县| 阿鲁科尔沁旗| 龙泉市| 齐河县| 松江区| 和林格尔县| 秭归县| 随州市| 利辛县| 信丰县| 固阳县| 陵川县| 通渭县| 莲花县| 廊坊市| 丹棱县| 泗洪县| 安岳县| 天镇县| 田林县| 邳州市| 宁远县| 施秉县| 镶黄旗|