Mastering Memory Management
The Art of Efficient Memory Allocation
When a system runs out of available page frames in its main memory, it’s forced to evict a page frame to make room for new data. But what happens when the page to be evicted has been modified since it was last loaded from disk? In this scenario, the page must be written back to disk before it can be replaced, a process known as paging.
Not All Operating Systems Are Created Equal
Interestingly, not all operating systems that support virtual memory also support paging. For instance, iOS and Android take a different approach. When their main memory is full, they terminate processes until enough free memory is available again. This approach avoids writing memory pages back to disk, which can drain the battery and shorten the lifespan of flash storage.
Understanding Virtual Memory
Let’s take a closer look at how virtual memory works. In the diagram below, we see two running processes, each with its own virtual memory space. Some pages are mapped to physical memory, while others are not. When a process needs to access a memory page that’s not in physical memory, a page fault occurs, and the page is mapped to a vacant memory frame.
The Dangers of Thrashing
But what happens when a system runs low on physical memory and is constantly paging? This can lead to a phenomenon known as thrashing, where the system spends all its time loading and unloading memory pages, causing performance to grind to a halt. To avoid thrashing, it’s essential to monitor page fault frequency and optimize memory allocation.
Memory Management in C++
So, how does memory management work in C++? The stack and heap are the two most critical memory segments in a C++ program. The stack is where local variables reside, while the heap is a global memory area shared among all threads. Understanding how these memory segments work is crucial for optimizing performance.
The Stack and Heap in Action
The stack grows each time a function is called and contracts when a function returns. Each thread has its own stack, making it thread-safe. The heap, on the other hand, grows when we allocate memory with new or malloc() and contracts when we free memory with delete or free(). As shown in the diagram below, the stack and heap grow in opposite directions in a virtual address space.
By grasping the fundamentals of memory management, developers can write more efficient, high-performance code that takes full advantage of system resources.