메모리(Memory)의 배치

메모리(Memory)의 배치

Solidity는 네 개의 32바이트 슬롯을 예약해 두고, 특정 바이트 범위(끝점 포함)를 다음과 같이 사용해요. 메모리 배치는 스토리지 배치와 다르기 때문에, 이 차이를 헤아려야 정확하게 동작해요.

출처: 문서

본문

Solidity는 네 개의 32바이트 슬롯을 예약하며, 특정 바이트 범위(끝점 포함)를 다음과 같이 사용해요:

  • 0x00 - 0x3f (64바이트): 해시 메서드를 위한 스크래치 공간(scractch space)
  • 0x40 - 0x5f (32바이트): 현재 할당된 메모리 크기(일명 자유 메모리 포인터, free memory pointer)
  • 0x60 - 0x7f (32바이트): 제로 슬롯(zero slot)

스크래치 공간은 문장 사이(즉 인라인 어셈블리 안에서) 사용할 수 있어요. 제로 슬롯은 동적 메모리 배열의 초기 값으로 사용되며, 절대 써서는 안 돼요(자유 메모리 포인터는 처음에 0x80을 가리켜요).

Solidity는 항상 새 객체를 자유 메모리 포인터에 배치하고, 메모리는 결코 해제되지 않아요(이는 미래에 바뀔 수 있어요). Solidity 메모리 배열의 요소는 항상 32바이트의 배수를 차지해요(bytes1[]의 경우에도 마찬가지지만, bytes와 string은 예외예요). 다차원 메모리 배열은 메모리 배열에 대한 포인터예요. 동적 배열의 길이는 배열의 첫 번째 슬롯에 저장되고, 그 뒤로 배열 요소들이 이어져요.

경고 (Warning)

Solidity에는 64바이트보다 큰 임시 메모리 영역이 필요해서 스크래치 공간에 들어가지 못하는 연산들이 있어요. 그런 연산들은 자유 메모리가 가리키는 위치에 배치되지만, 수명이 짧기 때문에 포인터는 갱신되지 않아요. 그 메모리는 0으로 채워지거나 채워지지 않을 수 있어요. 그러므로 자유 메모리가 0으로 채워진 영역을 가리킬 거라고 기대하면 안 돼요. msize를 사용해 확실히 0으로 채워진 메모리 영역을 얻는 게 좋아 보일 수 있지만, 자유 메모리 포인터를 갱신하지 않고 그런 포인터를 비임시적으로 사용하면 예상치 못한 결과가 생길 수 있어요.

스토리지 배치와의 차이점 (Differences to Layout in Storage)

위에서 설명했듯 메모리 배치는 스토리지 배치와 달라요. 아래에 몇 가지 예시가 있어요.

배열에서의 차이 예시 (Example for Difference in Arrays)

다음 배열은 스토리지에서는 32바이트(1 슬롯)를 차지하지만, 메모리에서는 128바이트(각각 32바이트인 항목 4개)를 차지해요.

open in Remix

uint8[4] a;

구조체 배치에서의 차이 예시 (Example for Difference in Struct Layout)

다음 구조체는 스토리지에서는 96바이트(32바이트 슬롯 3개)를 차지하지만, 메모리에서는 128바이트(각각 32바이트인 항목 4개)를 차지해요.

open in Remix

struct S {
    uint a;
    uint b;
    uint8 c;
    uint8 d;
}

더 알아보기 (Learn more)