1 寫緩存區
- 現代的處理器使用寫緩沖區臨時保存向內存寫入的數據。
- 優點:寫緩沖區可以保證指令流水線持續運行,它可以避免由于處理器停頓下來等待向內存寫入數據而產生的延遲。同時,通過以批處理的方式刷新寫緩沖區,以及合并寫緩沖區中對同一內存地址的多次寫,減少對內存總線的占用。
- 不足:雖然寫緩沖區有這么多好處,但每個處理器上的寫緩沖區,僅僅對它所在的處理器可見。
- 影響:這個特性會對內存操作的執行順序產生重要的影響:處理器對內存的讀/寫操作的執行順序,不一定與內存實際發生的讀/寫操作順序一致!
2 現代的處理器都會允許對寫-讀操作進行重排序
- 由于寫緩沖區僅對自己的處理器可見,它會導致處理器執行內存操作的順序可能會與內存實際的操作執行順序不一致。
- 由于現代的處理器都會使用寫緩沖區,因此現代的處理器都會允許對寫-讀操作進行重排序。
具體示例
qq_pic_merged_1533142189908.jpg
假設處理器A和處理器B按程序的順序并行執行內存訪問,最終可能得到x=y=0的結果。
處理器和內存交互.jpg
- 這里處理器A和處理器B可以同時把共享變量寫入自己的寫緩沖區(A1,B1),然后從內存中讀取另一個共享變量(A2,B2),最后才把自己寫緩存區中保存的臟數據刷新到內存中(A3,B3)。當以這種時序執行時,程序就可以得到x=y=0的結果。
- 從內存操作實際發生的順序來看,直到處理器A執行A3來刷新自己的寫緩存區,寫操作A1才算真正執行了。雖然處理器A執行內存操作的順序為:A1→A2,但內存操作實際發生的順序卻是A2→A1。此時,處理器A的內存操作順序被重排序了(處理器B的情況和處理器A一樣)
3 常見處理器允許的重排序類型
qq_pic_merged_1533142674052.jpg
- 單元格中的“N”表示處理器不允許兩個操作重排序,“Y”表示允許重排序。
- 常見的處理器都允許Store-Load重排序;
- 常見的處理器都不允許對存在數據依賴的操作做重排序。
- 由于ARM處理器的內存模型與PowerPC處理器的內存模型非常類似,
4 java內存屏障
為了保證內存可見性,Java編譯器在生成指令序列的適當位置會插入內存屏障指令來禁止特定類型的處理器重排序。
JMM把內存屏障指令分為4類
qq_pic_merged_1533143037391.jpg
-
StoreLoad Barriers
是一個“全能型”的屏障,它同時具有其他3個屏障的效果。 - 現代的多處理器大多支持該屏障(其他類型的屏障不一定被所有處理器支持)。
- 執行該屏障開銷會很昂貴,因為當前處理器通常要把寫緩沖區中的數據全部刷新到內存中(Buffer Fully Flush)。
參考
《java并發編程的藝術》