以太坊虛擬機
EVM 記憶體
記憶體是 EVM 的暫時草稿空間——一塊空白、可依位元組定址的陣列,合約執行時能對它讀寫,呼叫一結束便瞬間清空。它是合約用來組裝那些大到塞不進 32 位元組堆疊之物的地方:傳給另一份合約的引數、回傳的資料,以及陣列、字串這類動態結構。可以把它想成一塊白板:寬敞、好用,但每次會議後就被擦掉。
記憶體是線性的、起初為空;你以位元組偏移量定址。MSTORE 在某偏移處寫入完整的 32 位元組字,MSTORE8 寫入單一位元組,MLOAD 讀取 32 位元組。雖然你定址的是個別位元組,記憶體卻以 32 位元組的字為單位增長,EVM 會追蹤被觸及的最高字。讀寫超出當前大小之處,記憶體會悄悄擴張以涵蓋它——沒有獨立的「配置」步驟。
成本上的關鍵彎角,是記憶體擴張採二次式定價。把記憶體增長到 n 個字所需的總 gas 為 3*n + n²/512。對小範圍而言,線性的每字 3 這一項佔主導,記憶體幾乎像是免費;但 n²/512 這一項意味著把記憶體膨脹到數萬個字會變得貴得嚇人——這是刻意設下的煞車,防止合約妄圖配置數 GB 來騷擾節點。
依慣例,Solidity 保留記憶體最前面的幾個槽:位元組 0x00–0x3F 是供雜湊用的「暫存空間」,0x40 存放空閒記憶體指標(下一次配置可起始的偏移量),0x60 則是一個永遠為零的字。記憶體是按呼叫劃分且短暫的:巢狀的 CALL 會取得自己全新的記憶體,交易一完成,記憶體中的一切都不留存。若需要持久的狀態,合約必須改用儲存。
memory_cost(n words) = 3 * n + (n^2) / 512
二次項會懲罰極大量的記憶體配置。
記憶體在每次呼叫之間(而不只是每筆交易之間)都會清空:若合約 A 呼叫合約 B,B 以自己空白的記憶體執行,看不到 A 的記憶體——只能看到 A 明確傳入的 calldata。
另見