pic
Personal
Website

9b. Stack vs Heap

PhD in Economics

Introduction

Memory allocations are a fundamental process in computer programming. This occurs whenever a new object is created, and involves reserving memory space to store the object's values, typically in the computer's Random Access Memory (RAM). In turn, RAM is logically divided into two main areas: the stack and the heap. Importantly, these areas aren't physical locations, but rather conceptual models that govern how memory is managed.

The distinction is crucial for performance since memory allocations on the heap are a costly operation. This approach to handle memory requires searching for free memory, tracking memory information, and freeing unused memory (a process known as garbage collection). Stack allocations, by contrast, are simpler and therefore more efficient.

The performance difference between stack and heap allocations can be significant, quickly becoming a major performance bottleneck if the operation is performed repeatedly. This disparity in performance explains the common convention in programming, including Julia, where memory allocations will exclusively refer to heap allocations.

In the current section, we begin the exploration of memory allocations, by briefly comparing how the stack and the heap work.

Stack Allocations

In Julia, typical objects stored on the stack include integers, numbers, characters, and small fixed-size collections like tuples.

Objects on the stack are characterized by having a fixed size, precluding the possibility of dynamically growing or shrinking in size. These characteristics make allocating and deallocating memory on the stack extremely efficient.

The primary limitation of the stack is its limited capacity, making it suitable only for objects with a few elements. Indeed, attempting to allocate more memory than the stack can accommodate will result in a "stack overflow" error, causing program termination. And, even if an object fits on the stack, allocating too many elements can significantly degrade performance. [note] There's no hard and fast rule about how many elements are "too many". Benchmarking is the only reliable way to determine the performance consequences for each particular case. As a rough guideline, objects with more than 100 elements will certainly suffer from poor performance, while those with fewer than 15 elements are likely to benefit from stack allocation.

Heap Allocations

Common objects stored on the heap include arrays (such as vectors and matrices) and strings. Unlike the stack, the heap is designed to allocate and free memory in any order, allowing it to accommodate larger and more complex data structures. Thus, the heap can handle objects as large as the available RAM permits, which additionally could grow or shrink dynamically.

While the heap offers greater flexibility than the stack, its more complex memory management comes at the cost of slower performance. [note] To handle the memory of heap-allocated objects, Julia uses what's known as a garbage collector. This mechanism automatically identifies and frees memory no longer in use, which can be computationally expensive. Due to their reduced speed, Chapter 9 will outline approaches to minimizing heap allocations. Strategies for achieving this includes utilizing the stack whenever possible, and favoring mutation over the creation of new objects.