블록체인 학습
0 XP

storage vs memory

Solidity에서 변수가 어디에 저장되는지는 가스 비용과 코드의 동작 방식에 큰 영향을 줍니다. 이를 데이터 위치(data location)라고 부르는데, 같은 코드라도 이 위치를 어떻게 지정하느냐에 따라 실행 결과와 트랜잭션 수수료가 달라집니다.

EVM에는 대표적인 데이터 위치가 세 가지 있습니다. 이번 수업에서는 그중 영구 저장소인 storage와 임시 작업 공간인 memory를 먼저 살펴봅니다. 읽기 전용 입력 공간인 calldata는 다음 수업에서 다룹니다.

storage - 블록체인의 영구 저장소

storage는 블록체인에 영구적으로 기록되는 공간입니다. 모든 상태 변수(state variable)는 컨트랙트의 storage에 저장됩니다. 한 번 기록된 값은 트랜잭션이 끝나도 사라지지 않고, 블록체인 상태의 일부로 남습니다.

대신 비용이 비쌉니다. 빈 슬롯에 처음 값을 쓰는 SSTORE는 약 20,000 가스가 들고, 값을 읽는 SLOAD에도 수천 가스가 필요할 수 있습니다. 따라서 반드시 오래 보관해야 하는 데이터만 storage에 두는 것이 좋습니다.

memory - 함수 실행 중에만 존재하는 임시 공간

memory는 함수가 실행되는 동안에만 존재하는 임시 공간입니다. 함수 실행이 끝나면 memory에 있던 값은 모두 사라집니다. storage에 비해 읽기와 쓰기 비용이 훨씬 저렴하기 때문에, 계산 중간 결과를 담거나 storage 데이터를 잠시 복사해 작업할 때 유용합니다.

다만 memory도 완전히 공짜는 아닙니다. 사용하는 메모리 양이 커질수록 추가 가스가 붙고, 크게 확장할수록 그 증가 폭도 가팔라집니다.

상태 변수를 함수 안에서 memory로 복사하면 원본은 바뀌지 않습니다. 반대로 storage 참조를 수정하면 블록체인에 저장된 실제 값이 바뀝니다. 이 차이는 Solidity에서 자주 발생하는 버그의 원인입니다.

storage 참조 vs memory 복사

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
 
contract Locations {
    uint256[] public numbers;
 
    function demo() public {
        numbers.push(10);
 
        // storage 참조: 원본을 직접 수정한다
        uint256[] storage ref = numbers;
        ref[0] = 99; // numbers[0]이 99로 바뀐다
 
        // memory 복사: 복사본을 수정해도 원본은 그대로다
        uint256[] memory copy = numbers;
        copy[0] = 1; // numbers[0]은 여전히 99다
    }
}

uint, bool 같은 값 타입의 지역 변수는 데이터 위치를 따로 명시하지 않아도 됩니다. 하지만 배열, 구조체, 매핑 같은 참조 타입은 함수 안에서 사용할 때 storage 또는 memory를 명시해야 합니다.

반복문에서 storage 배열에 여러 번 접근해야 한다면, 필요한 값을 한 번 memory로 복사해 작업한 뒤 마지막에 결과만 storage에 저장하는 방식으로 가스를 줄일 수 있습니다.

정리하면, storage는 비싸지만 영구적이고, memory는 저렴하지만 일시적입니다. 데이터가 얼마나 오래 필요하고, 얼마나 자주 읽고 쓸지에 따라 적절한 위치를 선택해야 합니다.

Code Editor
에디터를 불러오는 중...
실행 결과

Run 버튼을 눌러 코드를 실행하세요.