storage vs memory
Solidity에서 변수가 어디에 저장되는가는 가스 비용과 동작 방식을 좌우하는 핵심 개념입니다.
이를 데이터 위치(data location) 라고 부르며, 같은 코드라도 데이터 위치를 어떻게 지정하느냐에 따라
실행 결과와 트랜잭션 수수료가 달라집니다. 먼저 storage 와 memory 의
차이를 정확히 살펴봅니다.
EVM에는 세 가지 주요 데이터 위치가 있습니다. 이번 수업에서는 그중 영구 저장소인 storage 와
임시 작업 공간인 memory 를 다루고, 읽기 전용 입력 공간인 calldata 는 다음 수업에서 살펴봅니다.
storage - 블록체인의 영구 저장소
storage 는 블록체인에 영구적으로 기록되는 공간입니다. 모든 상태 변수(state variable) 는
컨트랙트의 storage 에 자리 잡으며, 한 번 쓰면 트랜잭션이 끝나도 사라지지 않고 블록체인 상태의
일부가 됩니다. 그만큼 비용이 비싸서, 빈 슬롯에 처음 쓰는 SSTORE 는 약 20,000 가스,
읽는 SLOAD 도 수천 가스가 듭니다. 꼭 영구 보존이 필요한 데이터만 storage 에 두는 것이 원칙입니다.
memory - 함수 실행 중에만 존재하는 임시 공간
memory 는 함수가 실행되는 동안에만 존재하는 임시 공간입니다. 함수가 끝나면 내용이 모두
사라지며, storage 에 비해 읽기/쓰기 비용이 훨씬 저렴합니다. 복잡한 계산의 중간 결과를 담거나,
storage 데이터를 한 번 복사해 반복 작업할 때 유용합니다. 단, 메모리도 무한정 공짜는 아니어서
사용량이 커지면 가스가 2차(quadratic) 로 증가하는 점은 기억해 두세요.
상태 변수를 함수 안에서 memory 로 복사하면 원본은 바뀌지 않습니다. 반대로 storage 참조를
수정하면 블록체인의 실제 값이 변경됩니다. 이 차이가 버그의 단골 원인입니다.
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 는 "저렴하지만 휘발성"입니다.
데이터의 수명과 비용을 함께 따져 적절한 위치를 고르는 것이 심화 Solidity의 기본입니다.