記憶體階層與快取
空間區域性(spatial locality)
當你從圖書館書架上取下一本書,你接著想要的,往往就是緊鄰它的那一本——同主題、同系列,刻意放在一起。聰明的館員會遞給你一小疊相鄰的書,而不只是你點名的那一本。空間區域性就是資料中的這個模式:若程式存取某個記憶體位址,它很可能很快會存取附近的位址,因此一次抓回整片鄰域是划算的。
空間區域性正是快取不以單一位元組、而以整塊固定大小(稱為快取列,常見 64 位元組)為單位儲存的原因。當你要一個位元組而快取未命中,它會把整條包含該位元組的快取列拉進來——你的位元組加上它的鄰居——押注你接下來會想要那些鄰居。最熟悉的來源是陣列走訪:a[0]、a[1]、a[2]… 在記憶體中相連,所以一次快取列提取就把好幾個未來存取預先變成快速命中。循序提取指令也有同樣性質——下一道指令通常就在下一個位址。
這也是為什麼走訪順序能大幅改變速度。沿著二維陣列在記憶體中擺放的方式走(在 C 這種列優先語言裡逐列走),會依序踏過相連位址,享有空間區域性;反向走(逐行走)則每一步都跳過一整列的寬度,使快取列失效,在結果完全相同的情況下可能慢上好幾倍。誠實的提醒:空間區域性假設了合理的資料布局——若把資料散布到整個位址空間(例如各自獨立配置節點的鏈結串列),這項好處就大致蒸發了。
在 64 位元組的快取列與 4 位元組整數下,提取 a[0] 會在一次未命中中把 a[0..15] 帶進快取。接下來 15 次讀取都命中——所以向前掃陣列每 16 個元素才未命中一次。反向讀陣列或以大跨步讀,就把這項優勢丟掉了。
存取一個位址讓鄰近位址很可能成為下一個;快取以整列提取來善用這點。
空間區域性講的是位址上的「接近」,不是重用同一筆項目。對一個從不回頭的巨大陣列只向前掃一遍,有絕佳的空間區域性,卻幾乎沒有時間區域性。
又稱
另見