系統程式設計的前沿

持久記憶體(persistent memory)

數十年來有兩個乾淨的分類:快速的揮發性記憶體(RAM),CPU 可以一次讀寫一個位元組,但一斷電就立刻全失;以及緩慢的持久儲存(磁碟、SSD),它能撐過斷電,卻是透過一條漫長的軟體路徑、以大區塊為單位讀寫。持久記憶體是一類模糊了這條界線的硬體:它像 RAM 一樣可依位元組定址——CPU 能用普通指令載入與儲存個別位元組——卻又是非揮發的,所以斷電後內容依然存活。Intel 的 Optane DC 是這種儲存級記憶體最有名的例子。

具體而言,你可以把持久記憶體映射進你的定址空間,並把其中的資料結構當成普通記憶體來對待:用普通的儲存寫一個欄位、用普通的載入把它讀回,中間沒有 read()/write() 系統呼叫、也沒有區塊輸入輸出。陷阱在於持久化的順序。一次儲存會先抵達 CPU 的快取,而突然斷電可能丟失任何仍坐在快取裡的東西。要讓一次寫入真正持久,你必須把它從揮發性快取沖刷(flush)到持久媒介,並用一道屏障(fence)來排序——這就是「沖刷與屏障」紀律。所以一次審慎的更新是:寫入新資料、沖刷、屏障,再翻轉一個提交旗標、沖刷、屏障——這樣在復原時你才能分辨已完成的更新與只做一半的。把這個順序弄錯,你會得到看似寫了卻在當機時消失的資料,或一個只更新到一半的結構。

它之所以重要,是因為它承諾了一個真正嶄新的程式設計模型:以記憶體速度與記憶體粒度提供持久資料,無須序列化成區塊,且具有當機一致(crash-consistent)的記憶體內結構。但要老實面對現況。旗艦產品線(Optane)已停產,所以即便這些想法仍存活於研究、CXL 連接記憶體與電池備援設計之中,硬體的未來仍未底定;而且正確地對它寫程式確實很難——它要求與無鎖程式碼同樣審慎的順序推理,外加當機一致性的思考,這也是為何多數軟體至今仍把持久性當成儲存問題、而非記憶體問題。

// 在持久記憶體上的持久更新(沖刷與屏障): p->value = 42; // 普通儲存——仍只在快取裡 flush(&p->value); fence(); // 把它推到持久媒介,再排序它 p->committed = 1; // 現在標記它完成 flush(&p->committed); fence(); // 也讓提交旗標變得持久

一次對持久記憶體的當機一致寫入:普通儲存只到達快取,所以你把它沖刷到媒介,並用屏障在提交旗標之前先排序好資料。

可依位元組定址不代表自動持久:一次普通儲存會落在揮發性的 CPU 快取裡,在斷電時丟失,直到你把它沖刷並屏障到媒介。也要留意旗艦產品 Optane 已停產——這些想法仍具影響力,但硬體的走向確實尚未底定。

又稱
non-volatile memoryNVMstorage-class memoryOptane非揮發性記憶體PMEM