22/32 · 5 min
Dividing memory by meaning
Paging splits memory into equal blocks that mean nothing. Segmentation splits it by what the parts are for.
Segments
A program has parts with different properties:
code read only, executable, shared between processes
data read write, fixed size
heap read write, grows upward
stack read write, grows downwardA segmented address is a segment number plus an offset within it, and each segment has its own base, length and permissions.
What that buys
Protection that matches meaning. Code is marked non writable, so a bug cannot overwrite instructions. The stack is marked non executable, which is what stops a classic buffer overflow from running injected code. That protection is per segment because the segments mean something.
Sharing. Twenty copies of the same program share one physical copy of the code segment.
Bounds checking. An offset past the segment length is caught by hardware, which is where a segmentation fault comes from.
What it costs
Segments have different sizes, so external fragmentation returns exactly as in contiguous allocation. And a segment must be contiguous in physical memory, so a large growing heap can fail even with plenty free.
Both together
Modern systems segment for meaning and page for placement. Each segment is paged, so it need not be contiguous, and the permissions still apply per segment.
logical address -> segment number + offset
-> segment table gives a page table
-> page number + offset -> framex86 supported full segmentation and 64 bit mode largely abandoned it, keeping only enough to separate user and kernel. The naming survives everywhere else: the text, data, bss, heap and stack regions of a process are segments, and SIGSEGV is named after them.
| Paging | Segmentation | |
|---|---|---|
| Unit | fixed size | variable, logical |
| Visible to the programmer | no | yes |
| Fragmentation | internal | external |
| Protection granularity | per page | per logical region |