Hi everyone! I’m Adam and I recently started at DFINITY on the execution team. We thought there might be interest in a post describing how memory allocation works so here’s an overview. Hope it’s helpful!
Canister Memory
One advantage of the Internet Computer’s canister smart contracts over other smart contracts is that canisters can cheaply store data in addition to code. Here we’ll discuss how developers can reserve storage space for their canisters and how canisters are charged for the storage they use.
IC Storage Basics
IC canisters can store data in multiple ways:
- By allocating memory for the data on the wasm heap (as would happen using standard Rust or Motoko data structures).
- By storing the data in stable memory (via explicit calls to the system API to write to stable memory).
- By storing static data in the wasm binary itself (through, e.g. static objects or globals).
Canisters are periodically charged cycles for any memory they are using (including the memory used to store the wasm binary itself) and all kinds of memory usage are charged at the same rate.
Allocation
Developers have the option of choosing whether to reserve memory for their canisters or have them run on a best-effort basis.
- Reserved: If memory is reserved for a canister then the subnet will guarantee that the reserved amount of memory is free for the canister to use. However the canister will be charged for the full reserved amount, even if only a portion of it is used and the canister will not be able to use more than the reserved amount.
- Best-effort: If the canister is running on a best-effort basis then it is only charged for the actual memory in use, but there is the risk that the canister will not be able to run if it tries to expand its memory usage when there is not enough free space for it on the subnet.
The choice of whether to reserve memory for a canister or not and how much memory to reserve should weigh the cost of reserving additional memory against the risk of the canister being unable to run.
Viewing and Updating Settings
Developers can view the memory allocation settings for canisters with the dfx canister status
command:
$ dfx canister status hello Canister status call result for hello. Status: Running Controller: rwlgt-iiaaa-aaaaa-aaaaa-cai Memory allocation: 0 Compute allocation: 0 Freezing threshold: 2_592_000 Memory Size: Nat(360284) Balance: 4_000_000_000_000 Cycles Module hash: 0xb500708ce662300606d92bbab682ee373968233179a2b72d43a350107396b13b
Note that a memory allocation of 0 indicates that the canister is running on a best-effort basis. The memory currently in use by the canister can also be seen.
When creating a canister, the memory allocation can be set using the --memory-allocation
option of dfx canister create
. The memory allocation for an existing canister can be changed using the dfx canister update-settings
command with the --memory-allocation
option.
Costs
The current cost for memory usage on the IC is 127,000 cycles per GiB per second. This comes out to less than $6 per GiB per year. Full details of IC costs can be found in the docs and they may be changed in the future by an NNS proposal and vote. Note that there are also costs associated with ingress messages, so in addition to the storage costs there would be some additional charge for uploading data to a canister.
Limits
Currently canisters are limited to 12 GiB total memory usage. In addition, the wasm heap is limited to 4 GiB and stable memory is limited to 8 GiB.