
乍一看,關於 CPU 如何讀寫記憶體的問題似乎很簡單,但實際情況遠比表面複雜得多。CPU 並不會自行做出決策,它只是嚴格按照編譯器生成的指令執行。編譯器會將高階程式語言翻譯為機器指令,而這些機器指令最終告訴 CPU 去執行相應的操作。在 RISC(精簡指令集)架構下,資料不能直接從記憶體中獲取,必須通過 Load/Store 指令先搬運到暫存器中再進行操作。相比之下,x86 這種複雜指令集架構允許指令直接操作記憶體,也就是說,它可以直接從記憶體或暫存器中取數。除了資料之外,CPU 還會不斷地從記憶體中讀取下一條要執行的指令,因為在馮·諾依曼架構下,程式和資料是平等的,都存放在記憶體之中。正是這種雙重需求——既要取資料,又要取指令——驅動了 CPU 的記憶體訪問。問題在於速度:CPU 的運算速度極快,而記憶體的速度卻遠遠落後,兩者之間存在巨大的效能差距。為縮小差距,工程師引入了快取(Cache),並利用了程式的區域性性原理——時間區域性性(最近訪問過的資料很可能會再次訪問)和空間區域性性(與已訪問資料相鄰的資料很可能會被訪問)。快取使用 SRAM 構建,速度遠快於 DRAM,它位於 CPU 與主存之間,儲存高頻訪問的資料,避免 CPU 頻繁等待記憶體響應。即使快取容量很小,也能憑藉區域性性顯著提升效能。然而,寫操作帶來了複雜性:如果 CPU 更新了快取但沒有同步更新記憶體,就會產生資料不一致問題。為了解決這一點,通常有兩種策略:其一是寫直達(write-through),即同時更新快取和記憶體,方法簡單但速度較慢;其二是回寫(write-back),即先更新快取,再在需要時將資料寫回記憶體,這種方式更高效但實現更復雜。現代 CPU 進一步發展出了多級快取架構:L1(最小、最快)、L2(更大但稍慢)和 L3(容量更大但仍快於 DRAM)。CPU 會依次在各級快取中查詢,若未命中才訪問主存,從而在速度與成本之間取得平衡。在多核系統中,問題更加棘手。假設記憶體中的變數 X 初始值為 2,核心 C1 將其快取並更新為 4,而核心 C2 快取的是舊值 2,並在此基礎上加 4,最終寫回的結果是 6。正確結果應為 8,但由於多個核心的快取中存在不同副本,最終導致不一致。為解決這一問題,現代 CPU 引入了快取一致性協議,如 MESI 協議,用於確保不同核心的快取能夠保持同步。對程式設計師而言,這些細節同樣重要。程式如果具有良好的區域性性,就能更好地利用快取;反之,不合理的訪問模式會導致快取頻繁失效,效能下降。事實上,現代 CPU 晶片上有相當大一部分面積都用於快取設計,因為它是彌合 CPU 與記憶體速度鴻溝的關鍵。總的來說,CPU 訪問記憶體並不是一個簡單的過程,而是一個由編譯器、快取、多級結構以及一致性協議共同 orchestrate 的複雜系統,目的就是讓處理器能夠儘可能高效地運轉。在每一次看似簡單的讀寫操作背後,隱藏著支撐現代計算機效能的精密機制。