---
title: "Yul에서 메모리는 어떻게 작동할까?"
description: "Yul 스마트 컨트랙트 프로그래밍 언어에서 메모리가 작동하는 방식 알아보기"
---

# Yul에서 메모리는 어떻게 작동할까?

[Yul](http://www.alchemy.com/overviews/what-is-yul)은 [스마트 컨트랙트](https://www.alchemy.com/overviews/solidity-smart-contract) 내부에서 일종의 어셈블리 언어를 작성할 수 있는 중급 프로그래밍 언어입니다. Yul storage와 packed storage 변수를 읽고 쓰는 방법을 배웠다면, 이제 Yul 스마트 컨트랙트에서 memory가 어떻게 동작하는지 배워야 합니다.

## **Yul에서 memory는 어떻게 동작하는가?**

Memory는 [storage](http://www.alchemy.com/overviews/yul-storage)와는 다르게 동작합니다. Memory는 영속적이지 않으며, 함수 실행이 끝나면 모든 변수가 지워진다는 의미입니다.

Memory는 다른 언어의 heap과 비슷하지만, garbage collector가 없습니다.

Memory는 storage보다 훨씬 저렴합니다. 처음 22 word의 memory 비용은 선형으로 계산되지만, 그 이후로는 비용이 제곱으로 증가하므로 주의해야 합니다.

Memory는 32바이트 단위로 배치됩니다. 이 부분은 나중에 더 자세히 다루겠지만, 우선 0x00 - 0x20이 하나의 단위라는 점만 이해하면 됩니다 (slot처럼 생각해도 괜찮지만 실제로는 다른 개념입니다).

[Solidity](https://www.alchemy.com/overviews/solidity)는 0x00 - 0x40을 scratch space로 할당합니다. 이 영역이 비어있음이 보장되지는 않으며, 특정 연산에 사용됩니다.

0x40 - 0x60은 free memory pointer의 위치를 저장하며, 이는 memory에 새로운 값을 쓸 때 사용됩니다.

0x60 - 0x80은 gap으로 비워둡니다.

0x80부터가 실제 연산이 시작되는 지점입니다.

Memory는 값을 packing하지 않습니다. Storage에서 가져온 값은 각각 별도의 32바이트 단위에 저장됩니다 (예: 0x80-0xa0).

### **어떤 연산이 Yul에서 memory를 사용하는가?**

Memory는 다음과 같은 연산에 사용됩니다:

- 외부 호출의 반환 값
- 외부 호출을 위한 함수 값 설정
- 외부 호출에서 값 가져오기
- 에러 문자열과 함께 revert
- 로그 메시지
- keccak256\(\)으로 해시하기
- 다른 스마트 컨트랙트 생성

**memory와 관련된 유용한 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()와 비슷하지만, 단일 바이트에만 적용됩니다</p>", tooltip: "", icon: "" },
        id: 2,
      },
      {
        "1": { title: "<p>msize()</p>", tooltip: "", icon: "" },
        "2": { title: "<p>접근한 memory 인덱스 중 가장 큰 값을 반환합니다</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>실행을 종료하고, memory 위치 p - v의 데이터를 반환합니다</p>", tooltip: "", icon: "" },
        id: 5,
      },
      {
        "1": { title: "<p>revert(p, s)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>상태 변경을 저장하지 않고 실행을 종료하며, memory 위치 p - v의 데이터를 반환합니다</p>", tooltip: "", icon: "" },
        id: 6,
      },
    ],
  }}
/>

이제 몇 가지 데이터 구조를 더 살펴보겠습니다!

### **Yul에서 struct와 memory를 사용하는 방법**

Struct와 고정 배열은 사실 동일하게 동작하지만, 고정 배열은 이미 storage 섹션에서 다뤘으므로 여기서는 struct를 살펴보겠습니다. 다음 struct를 보겠습니다.

특별할 것 없는 단순한 struct입니다.

이제 코드를 살펴보겠습니다!

여기서는 s.subVar1을 memory 위치 0x80 - 0xa0에, s.subVar2를 memory 위치 0xa0 - 0xc0에 설정하고 있습니다. 그래서 0x80 - 0xc0을 반환하는 것입니다. 트랜잭션이 끝나기 직전의 memory 레이아웃을 표로 정리하면 다음과 같습니다.

<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>Scratch Space (Empty)</p>", tooltip: "", icon: "" },
        id: 0,
      },
      {
        "1": { title: "<p>0x20</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Scratch Space (Empty)</p>", tooltip: "", icon: "" },
        id: 1,
      },
      {
        "1": { title: "<p>0x40</p>", tooltip: "", icon: "" },
        "2": { title: "<p>0xc0 (Free Memory Pointer)</p>", tooltip: "", icon: "" },
        id: 2,
      },
      {
        "1": { title: "<p>0x60</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Empty</p>", tooltip: "", icon: "" },
        id: 3,
      },
      {
        "1": { title: "<p>0x80</p>", tooltip: "", icon: "" },
        "2": { title: "<p>s.subVar1: 0x20 (32 in decimal)</p>", tooltip: "", icon: "" },
        id: 4,
      },
      {
        "1": { title: "<p>0xa0</p>", tooltip: "", icon: "" },
        "2": { title: "<p>s.subVar1: 0x40 (64 in decimal)</p>", tooltip: "", icon: "" },
        id: 5,
      },
      {
        "1": { title: "<p>0xc0</p>", tooltip: "", icon: "" },
        "2": { title: "<p>New Free Memory Pointer. This is what msize() would return. (Empty)</p>", tooltip: "", icon: "" },
        id: 6,
      },
    ],
  }}
/>

**여기서 기억해야 할 점:**

- 0x00 - 0x40은 scratch space로 비어 있습니다
- 0x40은 free memory pointer를 알려줍니다
- Solidity는 0x60을 gap으로 남겨둡니다
- 0x80과 0xa0은 struct의 값을 저장하는 데 사용됩니다
- 0xc0은 새로운 free memory pointer입니다

memory 섹션의 마지막 부분에서는 dynamic array가 memory에서 어떻게 동작하는지 보여드리겠습니다. 이 예제에서는 파라미터 arr로 \[0, 1, 2, 3\]을 전달할 것입니다. 추가로, 이 예제에서는 배열에 요소를 하나 더 추가해보겠습니다. 이렇게 하면 다른 memory 변수를 덮어쓸 수도 있으니 실제 프로덕션에서는 주의해야 합니다.

**코드는 다음과 같습니다:**

**여기서 일어나는 일은 다음과 같습니다:**

- 배열이 memory의 어디에 저장되어 있는지 가져옵니다
- 배열의 첫 memory 위치에 저장된 배열의 길이를 가져옵니다
- 위치에 32바이트를 더해 \(배열의 길이 부분을 건너뛰어\) 다음으로 사용 가능한 위치를 확인합니다
- 배열의 길이에 32바이트를 곱해 다음 memory 위치로 이동합니다
- 새로운 값 \(4\)를 저장합니다
- 배열의 길이를 1 증가시킵니다
- free memory pointer를 업데이트합니다
- 배열을 반환합니다

memory 레이아웃을 다시 한번 살펴보겠습니다.

<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>Scratch Space (Empty)</p>", tooltip: "", icon: "" },
        id: 0,
      },
      {
        "1": { title: "<p>0x20</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Scratch Space (Empty)</p>", tooltip: "", icon: "" },
        id: 1,
      },
      {
        "1": { title: "<p>0x40</p>", tooltip: "", icon: "" },
        "2": { title: "<p>0x140 (Free Memory Pointer)</p>", tooltip: "", icon: "" },
        id: 2,
      },
      {
        "1": { title: "<p>0x60</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Empty</p>", tooltip: "", icon: "" },
        id: 3,
      },
      {
        "1": { title: "<p>0x80</p>", tooltip: "", icon: "" },
        "2": { title: "<p>New length of the array (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>Free Memory Pointer (Empty)</p>", tooltip: "", icon: "" },
        id: 10,
      },
    ],
  }}
/>

이것으로 memory 섹션을 마칩니다!

다음으로는 [Yul을 사용해 스마트 컨트랙트를 호출하는 방법](http://www.alchemy.com/overviews/yul-contract-calls)을 배우거나, 다시 돌아가서 [packed storage 변수를 읽고 쓰는 방법](http://www.alchemy.com/overviews/yul-packed-storage-variables)을 배워보세요!
