memory.c

Include dependency graph for memory.c:

digraph {
    graph [bgcolor="#00000000"]
    node [shape=rectangle style=filled fillcolor="#FFFFFF" font=Helvetica padding=2]
    edge [color="#1414CE"]
    "10" [label="stdbool.h" tooltip="stdbool.h"]
    "28" [label="dictionary.h" tooltip="dictionary.h"]
    "8" [label="atom.h" tooltip="atom.h"]
    "31" [label="trace.h" tooltip="trace.h"]
    "13" [label="assert.h" tooltip="assert.h"]
    "21" [label="synclist.h" tooltip="synclist.h"]
    "7" [label="stdint.h" tooltip="stdint.h"]
    "3" [label="stdlib.h" tooltip="stdlib.h"]
    "5" [label="context.h" tooltip="context.h"]
    "18" [label="utils.h" tooltip="utils.h"]
    "9" [label="atom_table.h" tooltip="atom_table.h"]
    "12" [label="term_typedef.h" tooltip="term_typedef.h"]
    "19" [label="stddef.h" tooltip="stddef.h"]
    "14" [label="limits.h" tooltip="limits.h"]
    "24" [label="refc_binary.h" tooltip="refc_binary.h"]
    "4" [label="string.h" tooltip="string.h"]
    "17" [label="mailbox.h" tooltip="mailbox.h"]
    "22" [label="term.h" tooltip="term.h"]
    "11" [label="erl_nif.h" tooltip="erl_nif.h"]
    "25" [label="resources.h" tooltip="resources.h"]
    "20" [label="smp.h" tooltip="smp.h"]
    "29" [label="erl_nif_priv.h" tooltip="erl_nif_priv.h"]
    "30" [label="tempstack.h" tooltip="tempstack.h"]
    "27" [label="debug.h" tooltip="debug.h"]
    "6" [label="globalcontext.h" tooltip="globalcontext.h"]
    "1" [label="/home/runner/work/AtomVM/AtomVM/src/libAtomVM/memory.c" tooltip="/home/runner/work/AtomVM/AtomVM/src/libAtomVM/memory.c" fillcolor="#BFBFBF"]
    "23" [label="memory.h" tooltip="memory.h"]
    "2" [label="stdio.h" tooltip="stdio.h"]
    "26" [label="timer_list.h" tooltip="timer_list.h"]
    "16" [label="list.h" tooltip="list.h"]
    "15" [label="inttypes.h" tooltip="inttypes.h"]
    "28" -> "16" [dir=forward tooltip="include"]
    "28" -> "22" [dir=forward tooltip="include"]
    "8" -> "7" [dir=forward tooltip="include"]
    "8" -> "3" [dir=forward tooltip="include"]
    "21" -> "2" [dir=forward tooltip="include"]
    "21" -> "16" [dir=forward tooltip="include"]
    "21" -> "20" [dir=forward tooltip="include"]
    "5" -> "6" [dir=forward tooltip="include"]
    "5" -> "16" [dir=forward tooltip="include"]
    "5" -> "17" [dir=forward tooltip="include"]
    "5" -> "20" [dir=forward tooltip="include"]
    "5" -> "22" [dir=forward tooltip="include"]
    "5" -> "26" [dir=forward tooltip="include"]
    "18" -> "19" [dir=forward tooltip="include"]
    "18" -> "2" [dir=forward tooltip="include"]
    "18" -> "3" [dir=forward tooltip="include"]
    "9" -> "10" [dir=forward tooltip="include"]
    "9" -> "8" [dir=forward tooltip="include"]
    "12" -> "13" [dir=forward tooltip="include"]
    "12" -> "14" [dir=forward tooltip="include"]
    "12" -> "15" [dir=forward tooltip="include"]
    "12" -> "7" [dir=forward tooltip="include"]
    "24" -> "10" [dir=forward tooltip="include"]
    "24" -> "3" [dir=forward tooltip="include"]
    "24" -> "16" [dir=forward tooltip="include"]
    "24" -> "25" [dir=forward tooltip="include"]
    "17" -> "10" [dir=forward tooltip="include"]
    "17" -> "16" [dir=forward tooltip="include"]
    "17" -> "12" [dir=forward tooltip="include"]
    "17" -> "18" [dir=forward tooltip="include"]
    "22" -> "10" [dir=forward tooltip="include"]
    "22" -> "7" [dir=forward tooltip="include"]
    "22" -> "2" [dir=forward tooltip="include"]
    "22" -> "3" [dir=forward tooltip="include"]
    "22" -> "4" [dir=forward tooltip="include"]
    "22" -> "23" [dir=forward tooltip="include"]
    "22" -> "24" [dir=forward tooltip="include"]
    "22" -> "18" [dir=forward tooltip="include"]
    "22" -> "12" [dir=forward tooltip="include"]
    "11" -> "12" [dir=forward tooltip="include"]
    "25" -> "3" [dir=forward tooltip="include"]
    "25" -> "11" [dir=forward tooltip="include"]
    "25" -> "16" [dir=forward tooltip="include"]
    "25" -> "23" [dir=forward tooltip="include"]
    "20" -> "10" [dir=forward tooltip="include"]
    "29" -> "5" [dir=forward tooltip="include"]
    "29" -> "23" [dir=forward tooltip="include"]
    "27" -> "5" [dir=forward tooltip="include"]
    "6" -> "7" [dir=forward tooltip="include"]
    "6" -> "8" [dir=forward tooltip="include"]
    "6" -> "9" [dir=forward tooltip="include"]
    "6" -> "11" [dir=forward tooltip="include"]
    "6" -> "16" [dir=forward tooltip="include"]
    "6" -> "17" [dir=forward tooltip="include"]
    "6" -> "20" [dir=forward tooltip="include"]
    "6" -> "21" [dir=forward tooltip="include"]
    "6" -> "22" [dir=forward tooltip="include"]
    "6" -> "26" [dir=forward tooltip="include"]
    "1" -> "2" [dir=forward tooltip="include"]
    "1" -> "3" [dir=forward tooltip="include"]
    "1" -> "4" [dir=forward tooltip="include"]
    "1" -> "5" [dir=forward tooltip="include"]
    "1" -> "27" [dir=forward tooltip="include"]
    "1" -> "28" [dir=forward tooltip="include"]
    "1" -> "29" [dir=forward tooltip="include"]
    "1" -> "6" [dir=forward tooltip="include"]
    "1" -> "16" [dir=forward tooltip="include"]
    "1" -> "23" [dir=forward tooltip="include"]
    "1" -> "24" [dir=forward tooltip="include"]
    "1" -> "30" [dir=forward tooltip="include"]
    "1" -> "22" [dir=forward tooltip="include"]
    "1" -> "31" [dir=forward tooltip="include"]
    "1" -> "18" [dir=forward tooltip="include"]
    "23" -> "7" [dir=forward tooltip="include"]
    "23" -> "3" [dir=forward tooltip="include"]
    "23" -> "11" [dir=forward tooltip="include"]
    "23" -> "12" [dir=forward tooltip="include"]
    "23" -> "18" [dir=forward tooltip="include"]
    "26" -> "10" [dir=forward tooltip="include"]
    "26" -> "7" [dir=forward tooltip="include"]
    "26" -> "16" [dir=forward tooltip="include"]
}

Defines

MAX(a, b) ((a) > (b) ? (a) : (b))
MEMORY_SHRINK memory_gc
FIBONACCI_HEAP_GROWTH_REDUCTION_THRESHOLD 10000

Functions

static void memory_scan_and_copy(HeapFragment *old_fragment, term *mem_start, const term *mem_end, term **new_heap_pos, term *mso_list, bool move)
static term memory_shallow_copy_term(HeapFragment *old_fragment, term t, term **new_heap, bool move)
static enum MemoryGCResult memory_gc(Context *ctx, size_t new_size, size_t num_roots, term *roots)
enum MemoryGCResult memory_init_heap(Heap *heap, size_t size)

Initialize a root heap.

This function should be balanced with memory_destroy_heap or memory_destroy_heap_from_task if the heap is created by a driver task.

Parameters:
  • heap – heap to initialize.

  • size – capacity of the heap to create, not including the mso_list.

Returns:

MEMORY_GC_OK or MEMORY_GC_ERROR_FAILED_ALLOCATION depending on the outcome.

void memory_init_heap_root_fragment(Heap *heap, HeapFragment *root, size_t size)

Setup heap from its root. Set the mso_list to NIL and initialize heap_ptr.

Parameters:
  • heap – heap to initialize.

  • root – fragment root.

  • size – capacity of the heap to create, not including the mso_list.

static inline enum MemoryGCResult memory_heap_alloc_new_fragment(Heap *heap, size_t size)
enum MemoryGCResult memory_erl_nif_env_ensure_free(ErlNifEnv *env, size_t size)

makes sure that the given nif environment has given free memory

this function makes sure that at least size terms are available. When not available, a new fragment will be allocated.

Parameters:
  • env – the target environment.

  • size – needed available memory.

static size_t next_fibonacci_heap_size(size_t size)
enum MemoryGCResult memory_ensure_free_with_roots(Context *c, size_t size, size_t num_roots, term *roots, enum MemoryAllocMode alloc_mode)

makes sure that the given context has given free memory.

this function makes sure at least size terms are available. Optionally, it can allocate a fragment or shrink the heap to the specified size, depending on allocation strategy. The function can also be passed roots to update during any garbage collection.

Parameters:
  • ctx – the target context.

  • size – needed available memory.

  • num_roots – number of roots

  • roots – roots to preserve

  • alloc_mode – constraint on allocation of additional memory

static inline void push_to_stack(term **stack, term value)
static inline int memory_is_moved_marker(term *t)
static inline void memory_replace_with_moved_marker(term *to_be_replaced, term replace_with)
static inline term memory_dereference_moved_marker(const term *moved_marker)
static term memory_copy_term_tree_internal(term **heap_ptr, term *mso_list, term t)
term memory_copy_term_tree(Heap *new_heap, term t)

copies a term to a destination heap

deep copies a term to a destination heap, once finished old memory can be freed.

Parameters:
  • new_heap – the destination heap where terms will be copied.

  • t – term to copy

Returns:

a new term that is stored on the new heap.

term memory_copy_term_tree_to_storage(term *storage, term **heap_end, term t)

copies a term to a storage, typically for mailbox messages

deep copies a term to a destination heap, once finished old memory can be freed.

Parameters:
  • storage – storage for the copied data, should be large enough

  • heap_end – on output, pointer to the end of the term.

  • t – term to copy

Returns:

a boxed term pointer to the new term content that is stored in the storage.

unsigned long memory_estimate_usage(term t)

calculates term memory usage

perform an used memory calculation using given term as root, shared memory (that is not part of the memory block) is not accounted.

Parameters:
  • t – root term on which used memory calculation will be performed.

Returns:

used memory terms count in term units output parameter.

static inline bool memory_heap_fragment_contains_pointer(HeapFragment *old_fragment, term *ptr)
void memory_heap_append_fragment(Heap *heap, HeapFragment *fragment, term mso_list)

append a fragment to a heap. The MSO list is merged. The fragment will then be owned by the heap.

Parameters:
  • heap – the heap to append the fragment to

  • fragment – the fragment to add

  • mso_list – associated mso list or nil

void memory_sweep_mso_list(term mso_list, GlobalContext *global, bool from_task)

Sweep any unreferenced binaries in the “Mark Sweep Object” (MSO) list.

The MSO list is a list of term (references) in a heap. Currently, the elements of this list are referenced to reference-counted binaries or match binaries that themselves reference reference counted binaries. This function will iterate over the binaries in this list, and decrement the reference count of any elements that have not been marked for move (e.g., into a new heap). If the reference count reaches 0, then memory associated with the referenced binary will be freed.In a typical GC event, the terms in this list are within in the old heap or potentially in a heap fragment. However, this function may be called in a copy even, such as in a process spawn, or in the copy of a term to or from a process mailbox.

Parameters:
  • mso_list – the list of mark-sweep object in a heap “space”

  • global – the global context

  • from_task – boolean, true if called from a task, false otherwise