Memory Model for C

Different sections in the Memory#

Overview of the memory model#

graph TD
    classDef pointer fill:#f9d,stroke:#333;

    %% Main Vertical Structure
    MemoryModel["Memory Model"] --> Stack
    MemoryModel --> Heap
    MemoryModel --> Static

    %% Stack Section
    subgraph Stack["Stack - Function Activation Frames"]
        Frame1["Frame 1: main()"] --> Frame2["Frame 2: funcA()"]
        Frame2 --> Frame3["Frame 3: funcB()"]
        Frame3 -. "Pop on return" .-> Frame2
        StackPointer:::pointer -.-> HeapObj1
    end

    %% Heap Section
    subgraph Heap["Heap - Dynamic Memory"]
        HeapObj1[["Object A"]] --> HeapObj2[["Object B"]]
    end

    %% Static/Global Section
    subgraph Static["Static/Global Memory"]
        GlobalVar["Global Variables"] --> StaticVar["Static Variables"]
        StaticPointer:::pointer -.-> HeapObj2
    end

    class StackPointer,StaticPointer pointer;

Stack Implementations#

This stack is only the memory allocation executed by the instructions.

Activation Frame Layout#

  1. The basic type of memories:

    1. Frame pointer: the frame pointer is the previous stack pointer.
    2. Stack pointer: the lowest address in the stack (the top of the stack).
    3. Return address: the pointer pointing to the memory where the return value is stored.
    4. Return value: the value of the function return, pre-allocated in the previous activation frame.
  2. Activation Frame introduction:

    1. Why do we need it: as a simplified word to deliver the general process of function calling in the memory.

    2. When we detect a function call (function_next) in a function(function_prev), we do the activation frame:

      1. Bookkeeping( keep the RA/FP of the previous function)

      2. Input (the input variable the function_next need)

      3. Output( preallocate the return value of the function_next)

      4. Locals(allocate the locals of the function)

Detailed process for calling a function:#

During a main process execution, several steps occur sequentially:

  1. First, the Frame Pointer (FP) is set to establish the current stack frame’s reference point
  2. Local variables are allocated and initialized in the stack memory
  3. Important registers like the Return Address (RA) and Frame Pointer (FP) are preserved - this is called “bookkeeping”
  4. Space for return values (RV) is allocated
  5. Function parameters (inputs) are pushed onto the stack
  6. The program jumps to a function (like “foo”) using the “jal ra, foo” instruction

When the called function (“foo”) executes, it follows a similar procedure:

  1. It sets its own Frame Pointer (FP) at the current stack position
  2. Adjusts the Stack Pointer (SP) which allocates space for its local variables
  3. Executes its body code
  4. Saves any return values to the previously saved slot.
  5. Pops its locals from the stack when finished
  6. Returns control to the calling function using “jalr x0, ra, 0”

Upon return to the main process, the original function:

  1. Restores its bookkeeping information (RA, FP)
  2. Uses the return value (RV) as needed
  3. Pops any remaining locals from the function call
  4. Continues its execution

Heap Implementations#

Basic Heap Interfaces: dynamics allocation:#

Heap handles the malloc and frees in the memory

  • malloc(size_in_bytes), return a void pointer, and this is why you have to specify the type of the pointer every time you allocate.
  • free(ptr): deallocate the block pointed to by Ptr

General Memory Allocation Process#

  1. Request Phase
    When a program needs memory, it makes an explicit request using functions like malloc in C or the new operator in languages like Java or C++. The program specifies how much memory it needs.

  2. Block Location
    The heap manager searches for a suitable memory location:
    (This is where the heap memory policies are applied, for more information check the Heap allocation Poll)

  1. Allocation Execution
    Once a suitable location is found:

The heap manager marks that area as “in use” in its private data structures

It allocates slightly more memory than requested to accommodate metadata and alignment requirements

It returns a pointer (reference) to the usable portion of the allocated block

  1. Block Management
    After allocation:

The memory block’s location and size remain fixed

The block is reserved exclusively for the caller’s use—the heap won’t assign that same memory to other requests

The program accesses this memory through the returned pointer

Heap allocation Pollicies#

  • Strategy 1: First Fit
    • That is find the first space that is bigger than required.
    • Pro / Cons: fast but may waste space.
  • Strategy 2: Best fit
    • That is find the space of which has the smallest deviation from the desired space.
    • Pros / Cons: search for a block needs time but optimizes space.
  • Strategy 3: Mix fit
    • After searching like “number” of potential fits, choose the current best fit so far.

Statics memory#

The statics memory is allocated when the program begins and deallocated when the program ends.