Definition
Segmentation: Memory management dividing process into logical segments (code, data, stack, heap) with each segment mapped independently to physical memory. Segments vary in size.
Logical organization matching program structure unlike paging (fixed-size units).
Basic Segmentation Concept
Segments
Process divided into multiple logical segments:
Process Address Space:
┌─────────────────────┐
│ Text (Code) │ Segment 0
│ │ (read-only, sharable)
├─────────────────────┤
│ Initialized Data │ Segment 1
│ (globals) │ (read-write)
├─────────────────────┤
│ Uninitialized Data │ Segment 2
│ (bss) │
├─────────────────────┤
│ Heap │ Segment 3
│ (dynamic) │ (grows downward)
│ │
├─────────────────────┤
│ Stack │ Segment 4
│ (grows upward) │
└─────────────────────┘
Segment Table
Maps logical segments to physical addresses:
Segment | Base | Limit | Protection
────────┼───────┼───────┼────────────
0 | 0 | 4000 | R only (code)
1 | 4000 | 1500 | RW (data)
2 | 5500 | 2000 | RW (heap)
3 | 7500 | 3000 | RW (stack)
Logical Address
Two components:
Logical Address: (segment_number, offset)
Example:
(1, 500) → Segment 1, offset 500 bytes
Segment 1:
Base: 4000
Offset: 500
Physical: 4000 + 500 = 4500
Address Translation (Segmentation)
Step-by-Step
Logical Address: (2, 300)
Step 1: Extract segment number and offset
Segment Number: 2
Offset: 300
Step 2: Look up segment table
Segment_Table[2]:
Base: 5500
Limit: 2000
Step 3: Check offset valid
Offset (300) < Limit (2000)? YES
Step 4: Calculate physical address
Physical = Base + Offset
Physical = 5500 + 300
Physical = 5800
Step 5: Check protection
Segment allows read/write? YES
Access granted!
Segment Types and Usage
1. Code Segment
Contains: Program instructions
Size: Fixed (determined at compile time)
Characteristics:
- Read-only (re-entrant)
- Shareable (many processes use same code)
- Cannot grow
Example: Binary /usr/bin/ls
(same code shared by all users running ls)
2. Data Segment
Contains: Global variables
Size: Fixed (determined at compile time)
Characteristics:
- Read-write
- Not shareable (each process different values)
- Cannot grow
Example:
int globalCounter = 0;
char globalBuffer[1024];
3. Stack Segment
Contains: Local variables, return addresses, function parameters
Size: Dynamic (grows as needed)
Characteristics:
- Read-write
- Grows upward (toward higher addresses or downward)
- Shrinks when functions return
- Limit prevents overflow
Example:
void func() {
int localVar; // Pushed to stack
}
4. Heap Segment
Contains: Dynamically allocated memory
Size: Dynamic (grows as allocated)
Characteristics:
- Read-write
- Grows downward (toward higher addresses)
- Allocations fragmented
- malloc()/new() allocate from heap
Example:
int *arr = malloc(sizeof(int) * 1000);
Benefits of Segmentation
1. Logical Organization
Matches program structure:
Code ≠ Data ≠ Stack ≠ Heap
Different characteristics
Different segment sizes
Different protections
2. Dynamic Size
Segments grow as needed:
Program allocates memory:
Heap grows 10MB
Stack grows 5MB
Other segments unchanged
No need to pre-allocate total process size!
3. Sharing
Share segments between processes:
Process A Code Segment = Process B Code Segment (shared)
Process A Data Segment ≠ Process B Data Segment (separate)
File: /usr/bin/emacs (10MB)
Users: 1000
With sharing: 1 copy in memory (10MB)
Without sharing: 1000 copies (10GB!)
4. Protection
Different protections for segments:
Code segment: READ only (execute)
Data segment: READ/WRITE
Stack segment: READ/WRITE
Heap segment: READ/WRITE
Hardware enforces at segment level
5. Relocation
Segments can move independently:
Code segment: Physical 0-4000
Data segment: Physical 4000-5500
Heap segment: Physical 5500-7500
Rearrange for defragmentation:
Code segment: Physical 10000-14000
Data segment: Physical 14000-15500
Heap segment: Physical 15500-17500
Just update segment table!
Disadvantages of Segmentation
1. External Fragmentation
Free space becomes scattered:
After many allocation/deallocation:
Segment table:
Segment | Base | Limit
────────┼──────┼──────
0 | 0 | 1000
1 | 1000 | 500 (free)
2 | 2000 | 2000
3 | 4500 | 500 (free)
4 | 5000 | 1000
Free space: 500 + 500 = 1000 bytes total
But scattered! Can't fit 800-byte allocation!
Need compaction (expensive!)
2. Complexity
More complex than paging:
Segment table per process
Variable-size allocations
Complex allocation algorithms
Compaction handling
More OS overhead
3. Sharing Complexity
Segment sharing needs care:
Code segment shared (read-only): Safe
Data segment shared: Dangerous!
Two processes share data segment:
Process A modifies global variable
Process B sees modification
Synchronization issues!
Usually shared only for read-only code
4. Address Calculation
Address calculation more complex:
With paging (simple):
Physical = Frame * PageSize + Offset
With segmentation (complex):
Check segment exists
Check offset in limit
Add base
Hardware must be smart!
Segment table can be large
Paging vs Segmentation
| Feature | Paging | Segmentation |
|---|---|---|
| Unit Size | Fixed (4KB) | Variable (logical) |
| Address | Single number | (segment, offset) |
| Internal Frag | ~50% of page | None |
| External Frag | None | Significant |
| Logical Match | No (arbitrary) | Yes (structure) |
| Compaction | None needed | May be needed |
| Sharing | Difficult | Easy |
| Virtual Memory | Yes | Limited |
| Hardware Cost | Low | Medium |
Virtual Memory with Segmentation
Concept
Segments on disk when not used:
Segment 0 (Code): 4000 bytes, in memory
Segment 1 (Data): 1500 bytes, in memory
Segment 2 (Unused Heap): 1000MB, on disk
Segment 3 (Stack): 5000 bytes, in memory
Process seems to have 1000MB+
Actually using: ~10MB in memory
Rest on disk
Segment Fault
Access to segment not loaded:
Process accesses Segment 2 (on disk)
Segment Table[2]: Valid bit = 0 (not in memory)
Segment Fault!
Handler:
1. Load segment from disk
2. Set valid bit = 1
3. Retry instruction
Modern Use of Segmentation
Pure segmentation rarely used in modern systems
Why:
- External fragmentation (problem!)
- Complex management
- Paging simpler
Hybrid approach: Segmentation + Paging
Windows (x86):
Uses segmentation for process separation
Uses paging within each segment
Modern x86-64:
Segmentation mostly disabled
Pure paging used
Linux:
Paging predominantly
Minimal segmentation use
Example: Intel x86 Segmentation
Real Mode (16-bit)
Segmentation only (no paging)
Segment size: 64KB max
Segment base: Multiple of 16 bytes
Address: (segment, offset)
Physical = segment_base + offset
Protected Mode (32-bit)
Segmentation enabled
Segment size: Up to 4GB
Can add paging on top
Address: Selector (segment number) + offset
Selector used to look up segment descriptor
Descriptor provides: base, limit, protection
Summary
Segmentation divides process into logical segments matching program structure (code, data, stack, heap). Segments variable size, grow dynamically. Segment table maps logical segment+offset to physical address. Benefits: logical organization, protection, sharing, dynamic sizing. Disadvantages: external fragmentation, complexity, harder to implement efficient virtual memory. Modern systems prefer paging (simple, no external fragmentation) or hybrid (segmentation + paging). Segmentation mostly historical but understanding important for x86 protected mode and some specialized systems. Paging became dominant due to simplicity and efficiency.