https://juejin.im/post/6844904071166427143
L1,L2,L3
指的都是CPU
的緩存,他們比內存快,但是很昂貴,所以用作緩存,CPU
查找數據的時候首先在L1,然后看L2
,如果還沒有,就到內存查找一些服務器還有L3 Cache
,目的也是提高速度。
高速緩沖存儲器Cache
是位於CPU
與內存之間的臨時存儲器,它的容量比內存小但交換速度快。在Cache
中的數據是內存中的一小部分,但這一小部分是短時間內CPU
即將訪問的,當CPU
調用大量數據時,就可避開內存直接從Cache
中調用,從而加快讀取速度。由此可見,在CPU
中加入Cache
是一種高效的解決方案,這樣整個內存儲器(Cache+內存)
就變成了既有Cache
的高速度,又有內存的大容量的存儲系統了。Cache
對CPU
的性能影響很大,主要是因為CPU
的數據交換順序和CPU
與Cache
間的帶寬引起的。

高速緩存的工作原理
1. 讀取順序
CPU
要讀取一個數據時,首先從Cache
中查找,如果找到就立即讀取並送給CPU
處理;如果沒有找到,就用相對慢的速度從內存中讀取並送給CPU
處理,同時把這個數據所在的數據塊調入Cache
中,可以使得以后對整塊數據的讀取都從Cache
中進行,不必再調用內存。
正是這樣的讀取機制使CPU
讀取Cache
的命中率非常高(大多數CPU
可達90%左右),也就是說CPU
下一次要讀取的數據90%都在Cache
中,只有大約10%需要從內存讀取。這大大節省了CPU
直接讀取內存的時間,也使CPU
讀取數據時基本無需等待。總的來說,CPU
讀取數據的順序是先Cache后內存。
2. 緩存分類
前面是把Cache
作為一個整體來考慮的,現在要分類分析了。Intel
從Pentium
開始將Cache
分開,通常分為一級高速緩存L1
和二級高速緩存L2
。
在以往的觀念中,L1 Cache
是集成在CPU
中的,被稱為片內Cache
。在L1
中還分數據Cache(I-Cache)
和指令Cache(D-Cache)
。它們分別用來存放數據和執行這些數據的指令,而且兩個Cache
可以同時被CPU
訪問,減少了爭用Cache所造成的沖突,提高了處理器效能。
在P4處理器中使用了一種先進的一級指令Cache——動態跟蹤緩存。它直接和執行單元及動態跟蹤引擎相連,通過動態跟蹤引擎可以很快地找到所執行的指令,並且將指令的順序存儲在追蹤緩存里,這樣就減少了主執行循環的解碼周期,提高了處理器的運算效率。
以前的L2 Cache
沒集成在CPU
中,而在主板上或與CPU
集成在同一塊電路板上,因此也被稱為片外Cache
。但從PⅢ開始,由於工藝的提高L2 Cache
被集成在CPU
內核中,以相同於主頻的速度工作,結束了L2 Cache
與CPU大差距分頻的歷史,使L2 Cache
與L1 Cache
在性能上平等,得到更高的傳輸速度。L2Cache
只存儲數據,因此不分數據Cache
和指令Cache
。在CPU
核心不變化的情況下,增加L2 Cache
的容量能使性能提升,同一核心的CPU
高低端之分往往也是在L2 Cache
上做手腳,可見L2 Cache
的重要性。現在CPU
的L1 Cache
與L2 Cache
惟一區別在於讀取順序。
3. 讀取命中率
CPU
在Cache
中找到有用的數據被稱為命中,當Cache
中沒有CPU
所需的數據時(這時稱為未命中),CPU
才訪問內存。從理論上講,在一顆擁有2級Cache
的CPU
中,讀取L1 Cache
的命中率為80%
。也就是說CPU
從L1 Cache
中找到的有用數據占數據總量的80%,剩下的20%從L2 Cache
讀取。由於不能准確預測將要執行的數據,讀取L2的命中率也在80%左右(從L2讀到有用的數據占總數據的16%)。那么還有的數據就不得不從內存調用,但這已經是一個相當小的比例了。在一些高端領域的CPU
(像Intel
的Itanium
)中,我們常聽到L3 Cache
,它是為讀取L2 Cache
后未命中的數據設計的—種Cache
,在擁有L3 Cache
的CPU
中,只有約5%的數據需要從內存中調用,這進一步提高了CPU
的效率。
為了保證CPU
訪問時有較高的命中率,Cache
中的內容應該按一定的算法替換。一種較常用的算法是“最近最少使用算法”(LRU算法
),它是將最近一段時間內最少被訪問過的行淘汰出局。因此需要為每行設置一個計數器,LRU
算法是把命中行的計數器清零,其他各行計數器加1。當需要替換時淘汰行計數器計數值最大的數據行出局。這是一種高效、科學的算法,其計數器清零過程可以把一些頻繁調用后再不需要的數據淘汰出Cache
,提高Cache
的利用率。
緩存行填充
CPU
訪問內存時,並不是逐個字節訪問,而是以字長為單位訪問。比如32位的CPU
,字長為4字節,那么CPU
訪問內存的單位也是4字節。
這么設計的目的,是減少CPU
訪問內存的次數,加大CPU
訪問內存的吞吐量。比如同樣讀取8個字節的數據,一次讀取4個字節那么只需要讀取2次。
我們來看看,編寫程序時,變量在內存中是否按內存對齊的差異。有2個變量word1、word2
:
圖如下:

我們假設CPU
以4字節
為單位讀取內存。如果變量在內存中的布局按4字節對齊,那么讀取a變量只需要讀取一次內存,即word1
;讀取b變量也只需要讀取一次內存,即word2
。
而如果變量不做內存對齊,那么讀取a變量也只需要讀取一次內存,即word1
;但是讀取b變量時,由於b變量跨越了2個word
,所以需要讀取兩次內存,分別讀取word1
和word2
的值,然后將word1
偏移取后3個字節,word2
偏移取前1個字節,最后將它們做或操作,拼接得到b變量的值。
顯然,內存對齊在某些情況下可以減少讀取內存的次數以及一些運算,性能更高。
另外,由於內存對齊保證了讀取b變量是單次操作,在多核環境下,原子性更容易保證。
但是內存對齊提升性能的同時,也需要付出相應的代價。由於變量與變量之間增加了填充,並沒有存儲真實有效的數據,所以占用的內存會更大。這也是一個典型的空間換時間的應用場景。
參考文章
作者:簡棧文化
鏈接:https://juejin.im/post/6844904071166427143
來源:掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。