In the Ethereum Virtual Machine (EVM), memory is a fast, temporary workspace used during the execution of functions in smart contracts.
Technically, memory is a temporary, modifiable data location. It is also byte-addressable, meaning each byte in memory has a unique address. This allows smart contracts to read from or write to specific byte positions. Memory exists for the duration of a message call (i.e., the entire execution context of a contract call) and is cleared once execution completes.
Memory in the EVM is a linear byte array. It starts empty and expands when higher memory offsets are accessed or written to, with gas charged per 32-byte word used. Smart contracts use it for intermediate computation, manipulation of dynamic data structures, and building return values.
Unlike storage (persistent and expensive) or calldata (read-only, optimized for inputs), memory is volatile. It offers flexible, mutable access to data at a moderate gas cost. It is ideal for working with dynamic arrays, structs, or strings, especially within pure, view, or temporary computation contexts.
Memory is employed when data does not need to persist. It stores data temporarily during a function’s execution and clears it once the function ends.
Uses of memory:
string
, bytes
, or uint[]
require memory for in-function modifications.Modifiable: Data can be freely modified, making it useful for algorithmic processing and building return values.
Temporary: Data only lives for the duration of a message call. It is not retained across calls or stored on-chain.
Moderate gas cost: Because memory supports write operations and dynamic expansion, it is more expensive than calldata, but still significantly cheaper than storage.
Explicit allocation: Developers must use the memory
keyword when declaring dynamic variables like arrays, structs, or strings inside functions.
Loop counters and intermediate variables: Fast and mutable for calculations.
Modifying calldata: Calldata is read-only; copy to memory first if mutation is needed.
Dynamic data structures like strings and arrays: For in-function manipulation and return values.
Building return data: Arrays, structs, and strings are constructed in memory before being returned to the caller of the function.
In EVM Solidity smart contracts, there are four explicitly defined data locations, each with distinct purposes.
Here’s a quick comparison:
Property | Memory | Calldata | Storage | Transient storage (upcoming) |
---|---|---|---|---|
Modifiability | Mutable | Immutable (read-only) |
Mutable | Mutable |
Lifespan | Temporary (during a message call) | Temporary (during a message call) | Persistent (on-chain) | Temporary (during a transaction) |
Gas cost | Moderate | Low | High | Low to moderate |
Primary use | In-function computation | Function arguments for external calls | Long-term contract state | Temporary cross-functional data |
Note: Transient storage (EIP-1153) has been available in the EVM since the Shanghai upgrade using inline assembly, while native Solidity support is being developed.
Memory is the go-to location when you need temporary, editable data during function execution that doesn’t need to persist when the function ends.
// SPDX-License-Identifier: MIT
pragma solidity 0.8.27;
contract MemoryExample {
// Returns a modified copy of the input array
function doubleValues(uint256[] memory input) public pure returns (uint256[] memory) {
for (uint256 i = 0; i < input.length; i++) {
input[i] *= 2;
}
return input;
}
// Accepts a calldata string, copies to memory, and returns modified version
function appendHello(string calldata input) external pure returns (string memory) {
string memory result = string(abi.encodePacked(input, " Hello"));
return result;
}
}
Explanation:
doubleValues
: Accepts an array in memory and doubles each element in place before returning it.appendHello
: Copies a calldata
string into memory, appends Hello
, and returns the result.Memory is a flexible, modifiable, and temporary data location in the EVM. It’s useful for efficiently handling dynamic data structures during smart contract execution. While it incurs higher gas costs than calldata, it is essential for any logic that requires mutable, in-function data.
Mastering how and when to use memory helps developers write efficient, gas-optimized, and bug-resistant smart contracts.