閱讀922 返回首頁    go 阿裏雲 go 技術社區[雲棲]


有助於減少偽共享的@Contended注解

詳細描述看Aleksey Shipilev這封郵件 —— 我們期待@Contended已久。JVM會自動為對象字段進行內存布局。通常JVM會這樣做:(a)將對象的域按從大到小的順序排列,以優化占用的空 間;(b)打包引用類型的字段,以便垃圾收集器在追蹤的時候能夠處理相連的引用類型的字段。@Contended讓程序能夠更明確地控製並發和偽共享。通 過該功能我們能夠把那些頻繁進行寫操作的共享字段,從其它幾乎是隻讀或隻有少許寫操作的字段中分離開來。原則很簡單:對共享內容進行讀操作的代價小,對共 享內容的寫操作代價非常高。我們也可以將那些可能會被同一個線程幾乎同時寫的字段打包到一起。

一般而言,我們試圖改變相關字段的位置,以使得coherency misses的發生次數降到最低。在簡單的單線程環境中,那些在時間上緊挨在一起被訪問的字段,空間上應該放置在相鄰的位置以提升緩存局部性[1]。 也就是,時間局部性應該決定著空間局部性。時間上在一起訪問的字段應該放到空間上相鄰的位置。我們說過,當多線程並發訪問我們的字段的時候,我們必須小心 翼翼地以避免偽共享和因coherence traffic導致過多的緩存失效。同樣地,對於那些原本是分開的字段,但可能會被同一個線程同時寫入相同的緩存行,我們會試圖將這些字段聚集到一起。注 意:如果我們想極度地降低單線程下的容量缺失[2], 那麼在並發環境中可能出現大量的coherency misses。在原生C/C++代碼中,程序員都在使用能感知並發的(concurrency-aware)結構布局。@Contended也應在 JAVA中提供同樣的功能,雖然在本地代碼中,綁定字段到偏移量發生在編譯階段,但在JAVA中發生在裝載階段。值得指出的是,在一般情況下,找不到一個 同時適用於單線程和多線程環境的最優布局。理想布局問題本身就是一個NP難題。

理想情況下,JAVA虛擬機應該使用硬件的監控設施來檢測出共享行為,並在程序運行中改變布局。這是有一定困難的,因為我們還沒有好的辦法為JVM提供有效的信息。提示:我們需要取消操作係統和管理程序的中間層。另外一個挑戰是,原始字段的偏移量有在unsafe工具中使用,因此我們需要解決這個問題,可能是使用一個額外的中間層。

最後,眾所周知final字段是隻讀的,因此,我還希望能夠將它們打包到一起。

校注

[1]:早在1968年,Denning.P就曾提出局部性原理:程序在執行時將呈現出局部性規律,即在一較短的時間內,程序的執行僅局限於某個部分;相應地,它所訪問的存儲空間也局限於某個區域。

[2]:根據緩存缺失的原因,可以分為以下幾個類型:

  • 強製缺失(Compulsory Miss):任何數據在未被載入緩存前都會造成緩存缺失,必須先把數據從內存/上一級緩存載入當前緩存,才能繼續工作。由此帶來的缺失,稱為強製缺失。
  • 容量缺失(Capacity Miss):由於緩存容量小於內存/上一級緩存,使得數據不能全部載入緩存,由此帶來的缺失,叫做容量缺失。
  • 衝突缺失(Conflict Miss):緩存中,每個cache line(緩存中數據訪問的最小單位)會對應多處內存。之前的內存訪問刷新了cache line,由此導致的缺失,稱為衝突缺失。

文章轉自 並發編程網-ifeve.com

最後更新:2017-05-22 18:02:02

  上一篇:go  Java類_對象_變量
  下一篇:go  Java並發編程【1.2時代】