メモリ内のレイアウト
Solidityは4つの32バイトスロットを確保しており、特定のバイト範囲(エンドポイントを含む)は以下のように使用されます。
0x00
-0x3f
(64バイト): ハッシュ化のためのスクラッチ領域0x40
-0x5f
(32バイト): 現在割り当てられているメモリサイズ(別名: フリーメモリポインタ)0x60
-0x7f
(32バイト): ゼロスロット
スクラッチ領域は、文の間(インラインアセンブリ内)で使用できます。
ゼロスロットは、動的メモリ配列の初期値として使用され、決して書き込まれてはいけません(フリーメモリポインタは初期値として 0x80
を指します)。
Solidityは常に新しいオブジェクトをフリーメモリポインタに配置し、メモリは解放されません(これは将来変更されるかもしれません)。
Solidityのメモリ配列の要素は、常に32バイトの倍数を占めています(これは bytes1[]
でも当てはまりますが、 bytes
と string
では当てはまりません)。
多次元のメモリ配列は、メモリ配列へのポインタです。
動的配列の長さは、配列の最初のスロットに格納され、その後に配列要素が続きます。
警告
Solidityには、64バイト以上の一時的なメモリ領域を必要とする操作があり、そのためスクラッチ領域には収まりません。 これらはフリーメモリが指す場所に配置されますが、その寿命が短いため、ポインタは更新されません。 メモリはゼロになってもならなくても構いません。 このため、フリーメモリがゼロアウトされたメモリを指していると思ってはいけません。
確実にゼロになったメモリ領域に到達するために msize
を使用するのは良いアイデアに思えるかもしれませんが、空きメモリポインタを更新せずにそのようなポインタを非一時的に使用すると、予期しない結果になることがあります。
ストレージ内のレイアウトとの違い
以上のように、メモリ上のレイアウトと ストレージ 上のレイアウトは異なります。 以下、いくつかの例を紹介します。
配列における違いの例
次の配列は、ストレージでは32バイト(1スロット)ですが、メモリでは128バイト(32バイトずつの4つのアイテム)を占有します。
uint8[4] a;
構造体レイアウトにおける違いの例
次の構造体は、ストレージでは96バイト(32バイトのスロットが3つ)ですが、メモリでは128バイト(32バイトずつのアイテムが4つ)を占有します。
struct S {
uint a;
uint b;
uint8 c;
uint8 d;
}