-
Notifications
You must be signed in to change notification settings - Fork 18
Garbage_Collection_in_AtomVM
Warning
The following description is a conceptual overview and may omit low-level implementation details. The behavior of the garbage collector (GC) may vary depending on runtime conditions. For a complete and authoritative explanation, please refer to the official documentation: https://www.atomvm.net/doc/master/memory-management.html
The garbage collector in AtomVM is invoked on a per-process basis and operates on the memory of that specific process. This memory is conceptually divided into a stack and a heap — although it is commonly referred to altogether as "the heap."
Garbage collection may be triggered whenever any of the memory_ensure_free* family of functions is called.
If certain conditions are met (e.g., insufficient free space in the process heap), garbage collection will happen.
When GC is triggered, it performs the following steps:
- A new region of memory is allocated to serve as the new heap.
- Live (reachable) terms — i.e., values still in use — are identified and copied from the old heap to the new one.
- First, the essential terms are copied:
- Values on the process stack and in registers (e.g., arguments passed to NIFs or BIFs).
- Entries in the process dictionary.
- Then, recursively - by analysing the contents of newly copied terms - the terms referenced by them are copied as well. To avoid redundant copying, once a term is moved, its location in the old heap is replaced with a forwarding pointer of the form ``<<0x2B, new_heap_address>>`. This ensures subsequent traversals recognize that the term has already been copied.
- Recursion ends when no new terms are copied
- First, the essential terms are copied:
- Once all live data has been transferred, the old heap is discarded and associated memory is released.
After a GC cycle, terms created or referenced before collection may no longer be valid. This can happen under the following scenarios:
- A term has been relocated from the old heap to the new one.
- A term has been reclaimed because the GC determined it was unreachable and thus no longer needed.
To safely retain terms across a GC invocation, use the memory_ensure_free_with_roots function.
This variant accepts an array of term pointers (roots), representing terms that must remain valid.
If GC occurs during the operation, this function will update the values in the array to point
to the newly allocated versions of the terms — ensuring continued correctness,
provided you use the values from the roots array post-GC rather than stale local variables.
Important
After calling memory_ensure_free* never use terms other than ones passed as roots or stored in process dictionary
You should include in the roots array:
- Newly created terms that are not yet part of the stack, register set, or process dictionary (e.g., values created via `term_create_*`` functions).
- Terms already on the stack or in registers if you intend to use them after a potential GC operation.
Important
All terms passed as roots must be fully initialized before invoking GC. For example, partially constructed tuples (e.g., with unset or uninitialized elements) must not be included in the roots array. Doing so may result in the GC traversing undefined memory and attempting to interpret arbitrary bytes as valid terms, which can cause unpredictable behavior or system crashes.
By following these guidelines and leveraging memory_ensure_free_with_roots appropriately, you can write robust and memory-safe native code that cooperates correctly with AtomVM’s garbage collector.