Loading content...
Imagine a parking lot where cars must park in consecutive spaces. As cars come and go, gaps appear between parked vehicles. Eventually, you might have 10 empty spaces scattered across the lot, but no consecutive sequence of 5 spaces for a new truck. This is external fragmentation—free space exists but isn't contiguous, making it unusable for large allocations.
External fragmentation is the Achilles' heel of contiguous allocation. It's why this elegantly simple approach isn't used for general-purpose file systems despite its performance advantages.
By the end of this page, you'll understand how external fragmentation develops, its mathematical properties, how to measure fragmentation, and why it fundamentally limits contiguous allocation's applicability.
External fragmentation emerges naturally from the create-delete cycle of file operations. Let's trace through a sequence that demonstrates the problem:
Initial State: Empty disk with 100 contiguous free blocks
Step 1: Create files A (10 blocks), B (20 blocks), C (15 blocks), D (25 blocks)
Step 2: Delete files B and D
Result: 75 blocks free, but largest contiguous region is only 30 blocks. A 50-block file cannot be created despite having 75 blocks free.
| Metric | Value | Implication |
|---|---|---|
| Total Free Blocks | 75 | Appears to have plenty of space |
| Number of Free Regions | 3 | Space is scattered |
| Largest Contiguous Region | 30 | Maximum allocatable file size |
| Fragmentation Ratio | 60% | 1 - (30/75) = 0.60 |
The 50% Rule (empirically observed by Knuth) states that for systems using contiguous allocation with First Fit:
After reaching steady state, approximately 1/3 of memory holes are lost to fragmentation. If there are n allocated segments, there will be approximately n/2 holes.
This means external fragmentation is inherent to contiguous allocation—it's not a bug but a mathematical consequence of the allocation pattern.
Fragmentation Metrics:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
/* * Fragmentation Measurement and Analysis */ typedef struct { uint64_t total_free_blocks; /* Sum of all free regions */ uint64_t largest_free_extent; /* Biggest contiguous region */ uint32_t free_extent_count; /* Number of free regions */ double external_fragmentation; /* Primary metric */ double average_hole_size; /* Avg size of free regions */} fragmentation_metrics_t; void calculate_metrics(disk_t *disk, fragmentation_metrics_t *m) { /* Scan disk to find all free extents */ m->total_free_blocks = 0; m->largest_free_extent = 0; m->free_extent_count = 0; uint64_t current_extent = 0; for (uint64_t i = 0; i < disk->total_blocks; i++) { if (is_free(disk, i)) { current_extent++; m->total_free_blocks++; } else { if (current_extent > 0) { m->free_extent_count++; if (current_extent > m->largest_free_extent) m->largest_free_extent = current_extent; current_extent = 0; } } } /* Handle trailing extent */ if (current_extent > 0) { m->free_extent_count++; if (current_extent > m->largest_free_extent) m->largest_free_extent = current_extent; } /* Calculate metrics */ if (m->total_free_blocks > 0) { /* External fragmentation: how much free space is unusable */ m->external_fragmentation = 1.0 - ((double)m->largest_free_extent / m->total_free_blocks); m->average_hole_size = (double)m->total_free_blocks / m->free_extent_count; }} /* * Interpretation: * - external_fragmentation = 0.0: All free space is contiguous (optimal) * - external_fragmentation = 0.5: Half of free space is "trapped" * - external_fragmentation = 0.9: 90% of free space unusable for large files */Several factors influence how quickly and severely fragmentation develops:
External fragmentation creates serious operational problems:
| Problem | Description | Severity |
|---|---|---|
| Allocation Failure | Cannot create files despite free space | Critical |
| Space Waste | Free blocks trapped in unusable fragments | High |
| Allocation Time | Longer searches for suitable holes | Medium |
| User Confusion | "Disk full" with visible free space | High |
| System Instability | Critical operations may fail unexpectedly | Critical |
Consider a disk with 50% free space but severe fragmentation. A user sees "50 GB free" but cannot create a 1 GB file. From the user's perspective, the system is broken. This UX disaster is why general-purpose file systems abandoned pure contiguous allocation.
Systems using contiguous allocation need fragmentation monitoring to trigger preventive action before allocation failures occur:
Key Metrics to Monitor:
1234567891011121314151617181920212223242526
/* * Fragmentation Monitoring Thresholds */ typedef enum { FRAG_HEALTHY, /* < 20% fragmentation */ FRAG_WARNING, /* 20-50% fragmentation */ FRAG_CRITICAL, /* 50-80% fragmentation */ FRAG_EMERGENCY /* > 80% fragmentation */} fragmentation_level_t; fragmentation_level_t assess_fragmentation(double frag_ratio) { if (frag_ratio < 0.20) return FRAG_HEALTHY; if (frag_ratio < 0.50) return FRAG_WARNING; if (frag_ratio < 0.80) return FRAG_CRITICAL; return FRAG_EMERGENCY;} const char* recommended_action(fragmentation_level_t level) { switch (level) { case FRAG_HEALTHY: return "No action needed"; case FRAG_WARNING: return "Schedule compaction"; case FRAG_CRITICAL: return "Compact soon"; case FRAG_EMERGENCY: return "Immediate compaction"; }}You now understand external fragmentation—its causes, measurement, and consequences. Next, we'll explore the solution: compaction, and why it's both necessary and expensive.