CPU Cache模型

    計算機中,所有的運算操作都是由CPU的寄存器來完成的,CPU指令的執行過程需要涉及數據的讀取和寫入操作,CPU所能訪問的所有數據只能是計算機的主存(通常RAM)。

    CPU和主存兩邊的速度嚴重的不對等,通過傳統FSB(Front Side Bus)直接內存的訪問方式很明顯會導致CPU資源受到大量的限制,降低CPU整體的吞吐量,於是纔有了在CPU和主內存之間增加緩存的設計,緩存有一級緩存(一級緩存又分爲一級指令緩存和一級數據緩存)、二級緩存、三級緩存,主存到CPU之間的緩存的訪問速度是越來越快的,這種方式極大的提高了CPU的吞吐能力,緩存模型如下:

 

CPU Cache中的最小緩存單位是Cache Line,CPU緩存由許多個Cache Line構成,一個緩存行64個字節。由於緩存的出現,雖然提高了CPU的吞吐能力,但是同時也引入了緩存不一致的問題。比如在多線程時i++就可能會產生緩存不一致性的問題。主流的解決方案是:

1、鎖總線

2、通過緩存一致性協議

鎖總線是一種悲觀的實現方式,CPU和其他組建的通信都是通過總線(數據總線、控制總線、地址總線)來進行,如果採用總線加鎖的方式,則會阻塞其他CPU對其他組建的訪問,從而使得只有一個CPU能夠訪問這個變量的內存,這種方式效率低下,一般都是通過第二種方式來解決不一致的問題。

緩存一致性協議中的MESI協議保證了每個緩存中使用的共享變量副本都是一致的。當CPU在操作Cache中的數據時,如果發現該變量是一個共享變量,也就是說在其他的CPU Cache中也存在一個副本,那麼進行如下操作:

1、讀取操作,不做任何處理,只是將Cache中的數據讀取到寄存器。

2、寫入操作,發出信號通知其他CPU將該變量的Cache Line置爲無效狀態,其他CPU在進行該變量讀取的時候不得不到主內存中再次獲取。

 

這裏舉個栗子:如果x,y變量在一個緩存行裏,開啓兩個線程對x和y變量進行修改,那麼一個線程修改x/y變量時得通知另一個線程修改過了x/y變量,這樣會影響它的性能。

如果我們把x和y放在不同的緩存行裏,那麼它們之間就不會相互影響,這個也叫緩存行對齊。

 

補充知識:

一個java對象在內存中的存儲佈局:對象頭markword(8個字節)、類型指針class pointer(8個字節,經過壓縮後是4個字節)、實例數據instance data(看實際的數據大小,比如一個long類型對象佔8個字節),對齊padding(這塊是看前面的數據量能否被8個字節整除,不能纔去補齊,比如markword—8字節+class pointer—8字節+instance data—long類型+int類型—8+4字節,那麼padding就是4字節)。

那麼x所在的對象里加上一些冗餘的數據使得該對象爲64字節,那麼x和y就不在一個緩存行了。實際應用中,如disruptor就採用了緩存行對齊僞共享的技術提升了性能。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章