AiTechWorlds
AiTechWorlds
Imagine your work desk has limited surface space. Right now you have your current project spread out on it — documents, sticky notes, your laptop. In the filing cabinet beside you are older projects you finished last week. When your desk gets completely full and you need to start a new task, you gather up something you are not currently using and put it back in the cabinet to make room.
This is exactly what an operating system does — but for every single program running on your computer, simultaneously, in milliseconds. Memory management is the OS mechanism that decides what lives in RAM (your desk) and what gets pushed to disk (your cabinet), and it must do so fairly, quickly, and safely.
Modern computers run dozens of processes at once. Your browser, your music player, your terminal, your IDE — all of them need RAM. Without memory management:
The core problem: RAM is finite. Processes are many. The OS must share RAM fairly while keeping processes isolated from each other.
Memory management solves three distinct problems: allocation (giving processes memory), isolation (keeping processes out of each other's memory), and efficiency (using RAM without waste).
Before diving into allocation, you need to understand the two views of memory:
| Address Type | Who Sees It | What It Refers To |
|---|---|---|
| Physical Address | Hardware (RAM chips) | Actual location in RAM |
| Logical Address | Running process | Virtual location the process believes it has |
A process thinks it owns memory starting at address 0x0000. In reality, the OS has mapped that to physical address 0x4F00. The CPU's Memory Management Unit (MMU) performs this translation transparently.
This separation is foundational — it lets the OS place any process anywhere in physical RAM while the process believes it always starts at zero.
Early operating systems placed each process in a single contiguous (unbroken) block of RAM.
RAM is divided into fixed-size partitions at boot time. Each process gets one partition.
RAM (8 MB total)
+------------------+
| OS (2 MB) |
+------------------+
| Partition A | <- Process uses 1.5 MB, but partition is 2 MB
| 2 MB | 0.5 MB wasted!
+------------------+
| Partition B | <- Process uses 0.8 MB, partition is 2 MB
| 2 MB | 1.2 MB wasted!
+------------------+
| Partition C | <- EMPTY
| 2 MB |
+------------------+
Pros: Simple to implement, predictable
Cons: Internal fragmentation — wasted space inside a partition when the process is smaller than the partition
Partitions are created dynamically to fit each process exactly.
RAM after loading 3 processes:
+------------------+
| OS (2 MB) |
+------------------+
| Process A |
| 1.5 MB |
+------------------+
| Process B |
| 0.8 MB |
+------------------+
| Process C |
| 1.2 MB |
+------------------+
| Free (2.5 MB) |
+------------------+
Pros: No internal fragmentation
Cons: External fragmentation — free memory is scattered in small chunks that cannot satisfy large requests
Internal Fragmentation — wasted space inside an allocated block
Partition size: 4 KB
Process needs: 3 KB
Wasted: 1 KB [inside the block]
External Fragmentation — total free memory is enough, but it is scattered
Free: 1KB | Used | Free: 2KB | Used | Free: 1KB
Total free = 4 KB, but no single request for 3 KB can be satisfied.
External fragmentation is the more dangerous problem because it can halt new process creation even when "enough" memory exists.
One solution to external fragmentation is compaction — shuffling all processes to one end of RAM to create one large free block.
BEFORE compaction: AFTER compaction:
+----------+ +----------+
| Free 1KB | | Proc A |
+----------+ +----------+
| Proc A | ----> | Proc B |
+----------+ +----------+
| Free 2KB | | Proc C |
+----------+ +----------+
| Proc B | | FREE |
+----------+ | 4 KB |
| Free 1KB | +----------+
+----------+
| Proc C |
+----------+
Why it is expensive: Every process must be paused while its memory is physically moved. All pointers must be updated. On a busy system, this is like reorganizing a busy airport while flights are still landing.
Linux and modern OSes avoid compaction by using paging (covered in the next lesson) instead of contiguous allocation.
For contiguous allocation, the CPU uses two hardware registers per process:
Logical address: 0x0200
Base register: 0x4000
Limit register: 0x0500 (process owns 0x4000 to 0x44FF)
Physical address = Base + Logical = 0x4200 ✓
If logical address = 0x0600 (> Limit):
--> Hardware raises SEGMENTATION FAULT ✗
This hardware check happens on every memory access, in nanoseconds.
The OS enforces that Process A cannot read or write Process B's memory. This is not just policy — it is enforced in hardware:
Segmentation Fault on Linux)Real-world example: On Linux, if your C program dereferences a null pointer, the CPU immediately triggers a protection fault. The kernel sends SIGSEGV to your process and terminates it before it can corrupt any other process's memory.
On Windows, the same event produces a STATUS_ACCESS_VIOLATION exception.
| Concept | Problem Solved | Drawback |
|---|---|---|
| Fixed Partitioning | Simple allocation | Internal fragmentation |
| Variable Partitioning | No internal fragmentation | External fragmentation |
| Compaction | Fixes external fragmentation | Very expensive (pause all processes) |
| Base/Limit Registers | Memory protection | Only works for contiguous allocation |
| Logical/Physical split | Process isolation | Requires MMU hardware |
The real solution to fragmentation — used by every modern OS — is paging, which breaks memory into small fixed-size chunks and maps them independently. That is the subject of the next lesson.
Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises