一級緩存又分為數據緩存和指令緩存,他們都由高速緩存行組成,對於X86架構的CPU來說,高速緩存行一般是32個字節,早期的CPU大約只有512行高速緩存行,也就是說約16k的一級緩存。而現在的CPU一般都是32K以上的一級緩存。
當CPU需要讀取一個變量時,該變量所在的以32字節分組的內存數據將被一同讀入高速緩存行,所以,對於性能要求嚴格的程序來說,充分利用高速緩存行的優勢非常重要。一次性將訪問頻繁的32字節數據對齊後讀入高速緩存中,減少CPU高級緩存與低級緩存、內存的數據交換。
但是對於多CPU的計算機,情況卻又不一樣了。例如:
1、 CPU1 讀取了一個字節,以及它和它相鄰的字節被讀入 CPU1 的高速緩存。
2、 CPU2 做了上面同樣的工作。這樣 CPU1 , CPU2 的高速緩存擁有同樣的數據。
3、 CPU1 修改了那個字節,被修改後,那個字節被放回 CPU1 的高速緩存行。但是該信息並沒有被寫入RAM 。
4、 CPU2 訪問該字節,但由於 CPU1 並未將數據寫入 RAM ,導致了數據不同步。
當一個 CPU 修改高速緩存行中的字節時,計算機中的其它 CPU會被通知,它們的高速緩存將視為無效。於是,在上面的情況下, CPU2 發現自己的高速緩存中數據已無效, CPU1 將立即把自己的數據寫回 RAM ,然後 CPU2 重新讀取該數據。 可以看出,高速緩存行在多處理器上會導致一些不利。
從上面的情況可以看出,在設計數據結構的時候,應該盡量將只讀數據與讀寫數據分開,並具盡量將同一時間訪問的數據組合在一起。這樣 CPU 能一次將需要的數據讀入。
如:
Struct __a
{
Int id; // 不易變
Int factor;// 易變
Char name[64];// 不易變
Int value;// 易變
} ;
這樣的數據結構就很不利。
在 X86 下,可以試著修改和調整它
Struct __a
{
Int id; // 不易變
Char name[64];// 不易變
Char __Align[32 – sizeof(int)+sizeof(name)*sizeof(name[0])%32]
Int factor;// 易變
Int value;// 易變
Char __Align2[32 –2* sizeof(int)%32]
} ;
32 – sizeof(int)+sizeof(name)*sizeof(name[0])%32
32 表示 X86 架構中緩存中,高速緩存行為 32字節 大小。 __Align 用於顯式對齊。