Source: https://deepu.tech/memory-management-in-programming/

What?

  • When a software runs on a target OS on a computer, it needs to access to the computer’s RAM
    • load its own bytecode
    • store data values and data structures
    • load run-time systems
  • from two regions: Stack and Heap

Stack

  • used for static memory allocation.
  • Last in, first out (FIFO).
  • Storing and retrieving data from Stack very fast, there is no lookup required, only at its top.
  • Data that stored in the stack has to be finite and static (the size of data is known at compile time).
  • Execution stack (stack frames).
  • Each frame is a block of space where the data required for that function is stored.
  • For example: every time a function declares a new variable, it is “pushed” onto the top block in the stack.
  • Then every time the function exits, the top block is cleared, thus all the variable pushed onto stack by that function, are cleared.
  • Multithreaded applications can have a stack per thread.
  • Simple and straight forward and is done by the OS.
  • data that are stored on stack are local variables (value types or primitives, primitives constant), pointers and function frames.
  • Size limited, that leads to stack overflow errors

Heap

  • used for dynamic memory allocation
  • program needs to look up the data in the heap using pointers.
  • Slower than stack.
  • Dynamic size
  • Heap is shared among threads of an application.
  • Trickier to manage
  • used for global variables, references types like objects, strings, maps and other complex data structures.
  • Out of memory errors
  • no limit.

Different approaches in memory management

  • manual: C, and C++ provide malloc, realloc, calloc and free methods to manage memory
  • Garbage collection (GC)
    • Mark & Sweep GC: JVM, C#, Ruby, JavaScript. It contains two phases:
      • mark object is “alive”
      • sweep all object that is not.
    • Reference counting
      • every object gets a ref count which is incremented or decremented as refs to it change, and GC is done when the count becomes 0.
      • Cannot cyclic references
      • PHP, Python comes with workaround
      • This can be enabled in C++ as well.
  • Resource acquisition is initialization (RAII)
    • the object’s memory allocation is tied to its lifetime, which is from construction until destruction. It was introduced in C++ and also used by Ada and Rust.
  • Automatic Reference Counting (ARC):
    • similar to Ref Counting GC but instead of running a runtime process at a specific interval the retain and release instructions are inserted to the compile-time
    • when an object ref becomes to 0, it’s cleared automatically as part of execution without any program pause.
    • Cannot handle cyclic
    • relies on the developer to handle that by using certain keywords.
    • Clang compiler feature
    • Objective and Swift
  • Ownership
    • combines RAII with an ownership model.
    • When the owner goes out of scope the value will be dropped, freeing the memory regardless of it being in stack or heap.
    • Compile-time reference counting
    • Rust

Demystifying JVM Memory Management