Memory Management & GC
Relevant source files
The following files were used as context for generating this wiki page:
AtomVM provides a memory-managed environment specifically optimized for resource-constrained micro-controllers. The system utilizes efficient garbage collection (GC) and shared data mechanisms where permissible to minimize memory consumption and heap fragmentation. In AtomVM, memory management is primarily per-process, meaning each lightweight Erlang process maintains its own heap and can be garbage collected independently of others.
The architecture prioritizes space efficiency over performance in many scenarios, given that target devices often have as little as 128KB of addressable RAM. This design ensures that the BEAM's actor-based concurrency model can function effectively on tiny systems like the ESP32 and STM32.
Sources: doc/src/welcome-to-atomvm.md:14-38, doc/src/atomvm-internals.md:25-30
Heap Architecture
AtomVM employs a per-process heap structure. Each Context (Erlang process) contains a heap used for allocating terms such as tuples, lists, and boxed values.
Heap Growth Strategies
The virtual machine supports different strategies for heap growth to balance between memory availability and performance. For example, the MinimumHeapGrowth strategy ensures that the heap only grows by the minimum necessary amount, which is critical for devices with extremely limited RAM.
The diagram above shows the relationship between the process context and its internal memory structures.
Sources: doc/src/atomvm-internals.md:55-65, tests/test-heap.c:38-42
Component Memory Usage
| Component | Description | Memory Management |
|---|---|---|
| Process Heap | Local memory for Erlang terms within a process. | Per-process GC. |
| Heap Fragments | Temporary memory segments often used by ETS or signals. | Freed when node/table is deleted. |
| Refc Binaries | Large binary data shared across multiple processes. | Reference counting in GlobalContext. |
| Atom Table | Storage for unique Erlang atoms. | Global, persists for VM lifetime. |
Sources: doc/src/atomvm-internals.md:85-110, doc/src/atomvm-internals.md:415-430
Garbage Collection Logic
AtomVM uses a garbage collector to reclaim memory from processes. GC can be triggered automatically when an allocation fails to find sufficient free space or manually via specific signals.
Memory Ensure Free
The core mechanism for ensuring memory availability is memory_ensure_free. This function checks if the required amount of memory is available in the process heap. If not, it triggers a garbage collection cycle.
This flow illustrates the logic used by the VM to maintain available heap space.
Sources: src/libAtomVM/memory.h, tests/test-heap.c:45-55
Roots and Reachability
During GC, the system identifies "roots"—variables or terms currently in use by the process (such as variables on the stack or in the mailbox). Any memory not reachable from these roots is considered garbage and reclaimed. Functions like memory_ensure_free_with_roots allow the GC to run while explicitly preserving specific term references.
Sources: src/libAtomVM/memory.c, tests/test-heap.c:60-65
Shared Memory and Reference Counting
While most memory is process-local, large binaries and certain shared structures use reference counting to avoid expensive copying.
Reference Counted Binaries (Refc Binaries)
Large binaries are not stored on the process heap. Instead, they are stored in the GlobalContext and managed by a reference counter. Each process that references the binary holds a "boxed" reference on its local heap. When the process GC runs, it decrements the reference count if the binary is no longer reachable. When the count reaches zero, the global memory is freed.
This sequence shows how shared binaries are managed across different process lifecycles.
Sources: doc/src/atomvm-internals.md:100-105, tests/test-heap.c:85-115
ETS Memory Management
Erlang Term Storage (ETS) tables in AtomVM provide a way to store data across processes. Each entry in an ETS table is stored in its own Heap fragment.
- Allocation: When a tuple is inserted (via
ets:insert/2), the data is copied from the process heap into a newly allocated heap fragment owned by the ETS table. - Deallocation: When an entry is deleted or the table is destroyed, the associated heap fragments are immediately freed.
- Hashing: AtomVM uses a variant of the Character Folding hash algorithm to map keys to buckets without requiring additional memory allocation during the lookup process.
Sources: doc/src/atomvm-internals.md:415-445, doc/src/atomvm-internals.md:490-500
Conclusion
Memory management in AtomVM is a specialized system designed for high density in low-memory environments. By utilizing a combination of per-process heaps, global reference counting for large data, and strategic garbage collection, AtomVM enables complex concurrent Erlang and Elixir applications to run on hardware with severe RAM constraints. The integration of stacktrace information and line numbers is also managed carefully, as these features add non-trivial overhead and are often removed in production builds to conserve space.
Sources: doc/src/atomvm-internals.md:365-375, doc/src/welcome-to-atomvm.md:90-105