---
title: "Yulにおけるメモリの仕組み"
description: "Yulスマートコントラクトプログラミング言語におけるメモリの仕組みを解説"
---

# Yulにおけるメモリの仕組み

[Yul](http://www.alchemy.com/overviews/what-is-yul)は、[スマートコントラクト](https://www.alchemy.com/overviews/solidity-smart-contract)内でアセンブリ言語の一種を書くために使用できる中間言語です。Yulのstorageと、パックされたstorage変数の読み書き方法について学んだら、次はYulスマートコントラクトにおけるメモリの動作について学ぶことが重要です。

## **Yulにおけるメモリの動作**

メモリは[storage](http://www.alchemy.com/overviews/yul-storage)とは異なる動作をします。メモリは永続的ではなく、関数の実行が終わるとすべての変数がクリアされます。

メモリは他の言語におけるヒープに似ていますが、ガベージコレクタは存在しません。

メモリはstorageよりもはるかに安価です。最初の22ワードのメモリコストは線形に計算されますが、それ以降はメモリコストが二次関数的に増加するため注意が必要です。

メモリは32バイト単位で配置されます。詳しくは後述しますが、ここでは0x00 - 0x20が1つの単位であることを理解しておいてください（スロットのようなものと考えても構いませんが、両者は異なるものです）。

[Solidity](https://www.alchemy.com/overviews/solidity)は0x00 - 0x40をスクラッチスペースとして割り当てます。このメモリ領域が空であることは保証されておらず、特定の操作に使用されます。

0x40 - 0x60には、フリーメモリポインタと呼ばれるものの位置が格納されており、これは新しい値をメモリに書き込む際に使用されます。

0x60 - 0x80は空のギャップとして残されています。

0x80から実際の操作を開始します。

メモリは値をパックしません。storageから取得した値は、それぞれ独自の32バイト単位で格納されます（例：0x80-0xa0）。

### **Yulでメモリを使用する操作とは**

メモリは以下の操作で使用されます。

- 外部呼び出しの戻り値
- 外部呼び出しの関数値の設定
- 外部呼び出しからの値の取得
- エラー文字列を伴うrevert
- ログメッセージ
- keccak256\(\)によるハッシュ化
- 他のスマートコントラクトの作成

**メモリに関する便利なYul命令を紹介します：**

<EmbeddedTable
  table={{
    columns: [
      { key: "1", width: 200, title: "Instruction", dataType: "object" },
      { key: "2", width: 200, title: "Explanation", dataType: "object" },
    ],
    data: [
      {
        "1": { title: "<p>mload(p)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>sload()に似ていますが、pの後の32バイトをロードすることを意味します</p>", tooltip: "", icon: "" },
        id: 0,
      },
      {
        "1": { title: "<p>mstore(p, v)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>sstore()に似ていますが、値vをpからさらに32バイトの位置に格納することを意味します</p>", tooltip: "", icon: "" },
        id: 1,
      },
      {
        "1": { title: "<p>mstore8(p, v)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>mstore()に似ていますが、1バイトのみを対象とします</p>", tooltip: "", icon: "" },
        id: 2,
      },
      {
        "1": { title: "<p>msize()</p>", tooltip: "", icon: "" },
        "2": { title: "<p>アクセスされた中で最大のメモリインデックスを返します</p>", tooltip: "", icon: "" },
        id: 3,
      },
      {
        "1": { title: "<p>pop(x)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>値xを破棄します</p>", tooltip: "", icon: "" },
        id: 4,
      },
      {
        "1": { title: "<p>return(p, s)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>実行を終了し、メモリ位置p - vからデータを返します</p>", tooltip: "", icon: "" },
        id: 5,
      },
      {
        "1": { title: "<p>revert(p, s)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>状態変更を保存せずに実行を終了し、メモリ位置p - vからデータを返します</p>", tooltip: "", icon: "" },
        id: 6,
      },
    ],
  }}
/>

続いて、さらに別のデータ構造を見ていきましょう！

### **Yulでstructとメモリを使う方法**

structと固定長配列は実際には同じように動作しますが、固定長配列についてはすでにstorageのセクションで扱ったため、ここではstructを見ていきます。以下のstructをご覧ください。

特に変わったところはなく、単純なstructです。

それでは実際のコードを見てみましょう！

ここでは、s.subVar1をメモリ位置0x80 - 0xa0に、s.subVar2をメモリ位置0xa0 - 0xc0に設定しています。そのため、0x80 - 0xc0をreturnしています。トランザクション終了直前のメモリレイアウトを表にまとめると以下のようになります。

<EmbeddedTable
  table={{
    columns: [
      { key: "1", width: 200, title: "Memory Location", dataType: "object" },
      { key: "2", width: 200, title: "Value Stored", dataType: "object" },
    ],
    data: [
      {
        "1": { title: "<p>0x00</p>", tooltip: "", icon: "" },
        "2": { title: "<p>スクラッチスペース（空）</p>", tooltip: "", icon: "" },
        id: 0,
      },
      {
        "1": { title: "<p>0x20</p>", tooltip: "", icon: "" },
        "2": { title: "<p>スクラッチスペース（空）</p>", tooltip: "", icon: "" },
        id: 1,
      },
      {
        "1": { title: "<p>0x40</p>", tooltip: "", icon: "" },
        "2": { title: "<p>0xc0（フリーメモリポインタ）</p>", tooltip: "", icon: "" },
        id: 2,
      },
      {
        "1": { title: "<p>0x60</p>", tooltip: "", icon: "" },
        "2": { title: "<p>空</p>", tooltip: "", icon: "" },
        id: 3,
      },
      {
        "1": { title: "<p>0x80</p>", tooltip: "", icon: "" },
        "2": { title: "<p>s.subVar1: 0x20（10進数で32）</p>", tooltip: "", icon: "" },
        id: 4,
      },
      {
        "1": { title: "<p>0xa0</p>", tooltip: "", icon: "" },
        "2": { title: "<p>s.subVar1: 0x40（10進数で64）</p>", tooltip: "", icon: "" },
        id: 5,
      },
      {
        "1": { title: "<p>0xc0</p>", tooltip: "", icon: "" },
        "2": { title: "<p>新しいフリーメモリポインタ。これはmsize()が返す値です。（空）</p>", tooltip: "", icon: "" },
        id: 6,
      },
    ],
  }}
/>

**ここから分かること：**

- 0x00 - 0x40はスクラッチスペースとして空になっている
- 0x40はフリーメモリポインタを示している
- Solidityは0x60にギャップを残している
- 0x80と0xa0はstructの値の格納に使われている
- 0xc0は新しいフリーメモリポインタになっている

このメモリのセクションの最後に、動的配列がメモリ上でどのように扱われるかを見ていきます。この例では、パラメータarrとして\[0, 1, 2, 3\]を渡します。さらにこの例では、配列に要素を1つ追加してみます。ただし本番環境でこれを行う際は、別のメモリ変数を上書きしてしまう可能性があるため注意してください。

**コードは以下の通りです：**

**ここで行われていることは以下の通りです：**

- 配列がメモリ上のどこに格納されているかを取得する
- 配列の先頭のメモリ位置に格納されている、配列の長さを取得する
- その位置に32バイトを加算し（配列の長さ部分をスキップし）、次に使用可能な位置を確認する
- 配列の長さに32バイトを掛けて、次のメモリ位置まで進める
- 新しい値（4）を格納する
- 配列の長さを1増やして更新する
- フリーメモリポインタを更新する
- 配列をreturnする

もう一度メモリレイアウトを見てみましょう。

<EmbeddedTable
  table={{
    columns: [
      { key: "1", width: 200, title: "Memory Location", dataType: "object" },
      { key: "2", width: 200, title: "Value Stored", dataType: "object" },
    ],
    data: [
      {
        "1": { title: "<p>0x00</p>", tooltip: "", icon: "" },
        "2": { title: "<p>スクラッチスペース（空）</p>", tooltip: "", icon: "" },
        id: 0,
      },
      {
        "1": { title: "<p>0x20</p>", tooltip: "", icon: "" },
        "2": { title: "<p>スクラッチスペース（空）</p>", tooltip: "", icon: "" },
        id: 1,
      },
      {
        "1": { title: "<p>0x40</p>", tooltip: "", icon: "" },
        "2": { title: "<p>0x140（フリーメモリポインタ）</p>", tooltip: "", icon: "" },
        id: 2,
      },
      {
        "1": { title: "<p>0x60</p>", tooltip: "", icon: "" },
        "2": { title: "<p>空</p>", tooltip: "", icon: "" },
        id: 3,
      },
      {
        "1": { title: "<p>0x80</p>", tooltip: "", icon: "" },
        "2": { title: "<p>配列の新しい長さ（6）</p>", tooltip: "", icon: "" },
        id: 4,
      },
      {
        "1": { title: "<p>0xa0</p>", tooltip: "", icon: "" },
        "2": { title: "<p>arr[0]（0）</p>", tooltip: "", icon: "" },
        id: 5,
      },
      {
        "1": { title: "<p>0xc0</p>", tooltip: "", icon: "" },
        "2": { title: "<p>arr[1]（1）</p>", tooltip: "", icon: "" },
        id: 6,
      },
      {
        "1": { title: "<p>0xe0</p>", tooltip: "", icon: "" },
        "2": { title: "<p>arr[2]（2）</p>", tooltip: "", icon: "" },
        id: 7,
      },
      {
        "1": { title: "<p>0x100</p>", tooltip: "", icon: "" },
        "2": { title: "<p>arr[3]（3）</p>", tooltip: "", icon: "" },
        id: 8,
      },
      {
        "1": { title: "<p>0x120</p>", tooltip: "", icon: "" },
        "2": { title: "<p>arr[4]（4）</p>", tooltip: "", icon: "" },
        id: 9,
      },
      {
        "1": { title: "<p>0x140</p>", tooltip: "", icon: "" },
        "2": { title: "<p>フリーメモリポインタ（空）</p>", tooltip: "", icon: "" },
        id: 10,
      },
    ],
  }}
/>

以上でメモリに関するセクションは終わりです！

次は、[Yulを使ってスマートコントラクトを呼び出す方法](http://www.alchemy.com/overviews/yul-contract-calls)を学ぶか、[パックされたstorage変数の読み書き方法](http://www.alchemy.com/overviews/yul-packed-storage-variables)に戻って学び直してください！
