boy-learning-thread | 1.1.3 內(nèi)存屏障和CPU緩存

相關(guān)源碼:boy-learning-thread
個人博客:http://bruce.bugmakers.club
內(nèi)容來自《網(wǎng)易微專業(yè) - 高性能編程章節(jié)》

CPU 性能優(yōu)化手段 - 緩存

為了提高程序運行的性能,現(xiàn)代 CPU 在很多方面對程序進(jìn)行了優(yōu)化。

例如:CPU高速緩存。盡可能的避免處理器訪問主內(nèi)存的時間開銷,處理器大多會利用緩存(cache)以提高性能。

CPU 多級緩存

L1 Cache 一級緩存:CPU 第一層高速緩存,分為數(shù)據(jù)緩存和指令緩存。一般服務(wù)器 CPU 的 L1 緩存的容量通常在 32~4096KB。

L2 由于 L1 級高速緩存容量的限制,為了再次提高 CPU 的運算速度,在 CPU 外部放置一高速存儲器,即二級緩存。

L3 現(xiàn)在的都是內(nèi)置的。而它的實際作用即是,L3 緩存的應(yīng)用可以進(jìn)一步降低內(nèi)存延遲,同時提升大數(shù)據(jù)量計算時處理器的性能。具有較大 L3 緩存的處理器提供更有效的文件系統(tǒng)緩存行為及較短消息和處理器隊列長度。一般是多核共享一個 L3 緩存!

cpu 在讀取數(shù)據(jù)時,現(xiàn)在L1中尋找,再從L2中尋找,再從L3中尋找,然后是內(nèi)存,再后是外存儲器。

緩存同步協(xié)議

多 CPU 讀取同樣的數(shù)據(jù)進(jìn)行緩存,進(jìn)行不同的運算之后,最終寫入主內(nèi)存以哪個 CPU 為準(zhǔn)?

在這種高速緩存回寫的場景下,有一個緩存一致性協(xié)議多數(shù) CPU 廠商對他進(jìn)行了實現(xiàn)。

MESI 協(xié)議,他規(guī)定每條緩存有個狀態(tài)位,同時定義了下面四個狀態(tài):

  • 修改態(tài)(Modified)——此 cache 行已被修改過(臟行),內(nèi)容已不同于主存,為此 cache 專有;

  • 專有態(tài)(Exclusive)——此 cache 行內(nèi)容同于主存,但不出現(xiàn)與其他 cache 中;

  • 共享態(tài)(Shared)——此 cache 行同于主存,但也出現(xiàn)于其他 cache 中;

  • 無效態(tài)(Invalid)——此 cache 行內(nèi)容無效(空行)。

多處理器時,單個 CPU 對緩存中的數(shù)據(jù)進(jìn)行了改動,需要通知給其他 CPU。
也就是意味著,CPU 處理要控制自己的讀寫操作,還要監(jiān)聽其他 CPU 發(fā)出的通知,從而保證最終一致。

CPU 性能優(yōu)化手段 - 運行時指令重排

指令重排場景:當(dāng) CPU 寫緩存時,發(fā)現(xiàn)緩存區(qū)塊正在被其他 CPU 占用,為了提高 CPU 處理性能,可能將后面的讀緩存命令優(yōu)先執(zhí)行。

并非隨便重排,需要遵守 as-if-serial 語義。

as-if-serial 語義指的是:不管怎么重排序(編譯器和處理器為了提高并行度),(單線程)程序的執(zhí)行結(jié)果不能被改變。
編譯器,runtime 和處理器都必須遵守 as-if-serial 語義。也就是說,編譯器和處理器不會對存在數(shù)據(jù)依賴關(guān)系的操作做重排序。

兩個問題

1、CPU 高速緩存下,有一個問題:

緩存中的數(shù)據(jù)與主內(nèi)存的數(shù)據(jù)并不是實時同步的,各 CPU (或 CPU 核心)間緩存的數(shù)據(jù)也不是實時同步。

在同一個時間點,各 CPU 所看到同一內(nèi)存地址的數(shù)據(jù)的值可能是不一致的。

2、CPU 執(zhí)行指令重排序優(yōu)化下,有一個問題:

雖然遵守了 as-if-serial 語義,但僅在單 CPU 自己執(zhí)行的情況下能保證結(jié)果正確。

多核多線程中,指令邏輯無法分辨因果關(guān)聯(lián),可能出現(xiàn)亂序執(zhí)行,導(dǎo)致程序運行結(jié)果錯誤。

處理方式 —— 內(nèi)存屏障

處理器提供了兩個內(nèi)存屏障指令(Memory Barrier)用于解決上述兩個問題。

寫內(nèi)存屏障(Store Memory Barrier)

在指令后插入 Store Barrier,能讓寫入緩存中的最新數(shù)據(jù)更新寫入主內(nèi)存,讓其他線程可見。

強(qiáng)制寫入主內(nèi)存,這種顯示調(diào)用,CPU 就不會因為性能問題考慮而去對指令重排。

讀內(nèi)存屏障(Load Memory Barrier)

在指令前插入 Load Barrier,可以讓高速緩存中的數(shù)據(jù)失效,強(qiáng)制重新從主內(nèi)存中加載數(shù)據(jù)。

強(qiáng)制讀取主內(nèi)存內(nèi)容,讓 CPU 緩存與主內(nèi)存保持一致,避免了緩存導(dǎo)致的一致性問題。

小結(jié)

本章節(jié)內(nèi)容主要是對后續(xù) JVM 線程安全問題做的鋪墊。

同時,也看到了現(xiàn)代 CPU 不斷演進(jìn),在程序運行優(yōu)化中做出的努力。

不同 CPU 廠商所付出的人力物力成本,最終體現(xiàn)在不同 CPU 性能差距上。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容