A running computer is a crowded place. Your browser, a music player, a chat app, the window
manager, a dozen background helpers — each one is a
"A new process needs this much memory. Where do I put it?"
That question — how the OS hands out physical memory to processes — is the whole of
this page. We will place processes into RAM by hand, watch memory get chopped into unusable scraps,
and learn the first real trick for keeping order: segmentation. (The cleverer trick,
Memory sits in a hierarchy. CPU registers are blindingly fast but tiny; caches are fast and small; RAM is big and reasonably fast; the disk (SSD) is enormous but agonisingly slow. A CPU can only execute instructions that live in RAM — it cannot run code straight off the disk. So every process you launch must first be loaded into RAM, and it must be given a contiguous-enough patch of it to call home.
In the simplest scheme — contiguous allocation — each process gets one
single continuous block of physical addresses. The OS keeps a list of the holes
(free gaps) between the processes already in memory, and when a new process of size
Suppose memory currently has these five free holes, listed in address order from the bottom of RAM upward, and a new process arrives needing 212 KB:
Three classic placement policies answer "which hole?" differently:
Same request, same memory, three different homes. The leftover each policy creates is the key to everything that follows:
Here is that same RAM drawn as a vertical memory map — address 0 at the bottom, higher addresses climbing up. Grey striped blocks are free holes; solid coloured blocks are processes already resident. Press Play to watch first-fit scan up from the bottom and drop our 212 KB process into the first hole that fits, splitting it into a used part and a smaller free remainder.
Notice what placement does to the free space: the tidy 500 KB hole becomes 212 KB of process plus a new, smaller 288 KB hole. Every allocation tends to shave holes into ever-smaller pieces — which is exactly where our next problem comes from.
Fragmentation is free memory that exists on paper but can't actually be handed to a process. It comes in two very different flavours, and mixing them up is the classic exam mistake.
The memory-saver line: internal waste is trapped within a block; external waste is stranded between blocks. Contiguous allocation is especially prone to external fragmentation — every placement carves a hole into a used part and a smaller free part, and over time those remainders shrink into a confetti of unallocatable gaps.
Because a contiguous process needs a single run of consecutive addresses. Its code expects to jump to address 5,000 and find its own instructions there — not a stranger's. You cannot split it across two distant 300 KB holes and hope for the best.
One cure is compaction: pause everyone, slide all the live processes down to one
end of RAM so the holes merge into a single big one at the top, then resume. It works — but shuffling
gigabytes around is brutally expensive, and everything freezes while it happens. The real escape from
"needs one contiguous run" is
"Best-fit wastes the least memory, so it must be best." It is a trap. Best-fit picks the tightest hole, which means the leftover it creates is as small as possible — often a useless sliver like the 88 KB above. Do that thousands of times and you litter RAM with tiny holes nothing can use: best-fit is a champion producer of external fragmentation. Worst-fit leaves big, reusable leftovers, and plain first-fit is usually both faster and leaves memory less fragmented in practice. "Wastes the least right now" is not the same as "leaves memory healthiest over time."
And keep the two fragmentations straight: internal is a mistake about space inside an allocation (fixed block bigger than the request); external is a mistake about space between allocations (holes too scattered). A fixed-partition scheme suffers internal fragmentation; a variable contiguous scheme suffers external.
A program is not one featureless lump. It has a code segment (the instructions), a data segment (globals and the heap), and a stack (growing and shrinking as functions call each other). Segmentation takes this seriously: instead of one big contiguous block per process, the OS gives each logical segment its own block, placed independently in RAM.
Now an address is no longer a single number — it is a pair
Translating a logical address to a physical one is then two steps:
Say a process has this segment table:
That base + limit check is doing two jobs at once. It relocates the process (the same program can be loaded anywhere — just change the base), and it protects memory (a stray offset can never reach outside its own segment, so one process cannot scribble on another). This is where the dreaded "Segmentation fault (core dumped)" gets its name.
It helps: many small segments are far easier to slot into RAM's holes than one giant
contiguous block, so external fragmentation gets less severe. But segments are still
variable-sized contiguous blocks, so the holes-between-blocks problem never fully goes away. The idea
that finally kills external fragmentation is to chop memory into fixed-size pieces so any
free frame fits any need — and that idea is
The OS's memory job is a placement puzzle: fit variable-sized processes into a finite RAM.
Contiguous allocation with a placement policy (first-, best-, or
worst-fit) is the simplest answer, but it bleeds memory to fragmentation — internal
waste inside blocks, external waste between them. Segmentation softens the blow by
letting a process live as a handful of independently-placed, base-and-limit-protected pieces. To
finish the job — to stop worrying about holes entirely — we hand out memory in fixed-size chunks, which
is exactly what