Yul 中的記憶體如何運作?
Yul 是一種中階程式語言,可以用來在智能合約內撰寫組合語言。學會 Yul storage 以及如何讀寫 packed storage 變數之後,接下來要學習的是 memory 在 Yul 智能合約中如何運作。
Yul 中的 memory 如何運作?
Memory 的行為和 storage 不同。Memory 不是持久性的,也就是說函式執行結束後,所有變數都會被清除。
Memory 可以比擬為其他語言中的 heap,但沒有 garbage collector。
Memory 比 storage 便宜很多。前 22 個 word 的 memory 成本是線性計算的,但要小心,超過這個範圍後成本會變成二次方成長。
Memory 是以 32 byte 為單位排列的。稍後會更深入說明,但現在先了解 0x00 - 0x20 是一個序列(可以想成是一個 slot,如果這樣理解比較容易,但兩者其實不同)。
Solidity 將 0x00 - 0x40 配置為 scratch space。這段 memory 不保證是空的,會用於某些運算。
0x40 - 0x60 儲存的是 free memory pointer 的位置,用來寫入新資料到 memory 中。
0x60 - 0x80 是留空的間隔。
0x80 是我們開始進行操作的地方。
Memory 不會將數值 packed 在一起。從 storage 取出的值會各自存放在獨立的 32 byte 序列中(例如 0x80-0xa0)。
Yul 中哪些運算會用到 memory?
以下運算會用到 memory:
- External call 的回傳值
- External call 的函式設定值
- External call 取得的數值
- 用錯誤訊息 revert
- Log 訊息
- 用 keccak256() 進行雜湊運算
- 建立其他智能合約
以下是一些常用於 memory 操作的 Yul 指令:
接著我們來看看更多資料結構!
如何在 Yul 中使用 struct 和 memory
Struct 和 fixed array 的行為其實一樣,但由於我們已經在 storage 章節看過 fixed array,這裡就來看看 struct。請看以下這個 struct。
這裡沒有什麼特別之處,就是一個簡單的 struct。
現在來看一些程式碼!
這裡我們把 s.subVar1 設定在 memory 位置 0x80 - 0xa0,把 s.subVar2 設定在 memory 位置 0xa0 - 0xc0。這就是為什麼我們回傳的是 0x80 - 0xc0。以下是交易結束前的 memory 配置表。
從中可以歸納出以下重點:
- 0x00 - 0x40 為 scratch space,是空的
- 0x40 給我們 free memory pointer
- Solidity 在 0x60 留了一個間隔
- 0x80 和 0xa0 用來儲存 struct 的值
- 0xc0 是新的 free memory pointer
在 memory 這個章節的最後一部分,我要示範 dynamic array 在 memory 中是如何運作的。這個例子中我們會傳入 [0, 1, 2, 3] 作為參數 arr。作為額外示範,我們還會在這個陣列中新增一個元素。在正式環境這樣操作時要特別小心,因為可能會覆寫到其他 memory 變數。
程式碼如下:
這裡發生的事情是:
- 取得陣列在 memory 中的儲存位置
- 取得陣列的長度,這儲存在陣列的第一個 memory 位置
- 將位置加上 32 bytes(跳過陣列長度)以找到下一個可用位置
- 將陣列長度乘以 32 bytes,移動到下一個 memory 位置
- 儲存我們的新值(4)
- 將陣列長度更新加一
- 更新 free memory pointer
- 回傳陣列
我們再看一次 memory 的配置。
Memory 章節到此結束!
接下來,可以學習如何用 Yul 呼叫智能合約,或回去複習如何讀寫 packed storage 變數!
相關總覽

打造區塊鏈魔法
Alchemy 結合最強大的 Web3 開發者產品與工具,並提供資源、社群與卓越的支援。


