First Fit Memory Allocation is a classic greedy problem from operating systems. Given a set of free memory blocks and a list of processes, you place each process into the first block that is large enough. It is the simplest of the memory-allocation strategies, and the greedy choice ("take the first thing that works") is the whole lesson.
Problem. You are given an array blocks of free memory block sizes and an array processes of
process sizes. For each process in order, assign it to the first block (lowest index) that is large
enough to hold it, then shrink that block by the process size. Return the block index assigned to each
process, or -1 if no block could hold it.
Example: blocks = [100, 500, 200], processes = [212, 417, 112] → answer [1, -1, 1]
(P0 takes block 1 leaving 288, P1 fits nowhere, P2 takes block 1 leaving 176).
The slow way first
There is not really a "slower" brute force here — First Fit is the simple approach. The naive instinct might be to first sort blocks, or to search for the best-sized block (that is a different strategy called Best Fit). First Fit deliberately skips all that cleverness: it just walks the blocks from the left and stops at the first one that fits.
The question to ask: for this one process, which block do I commit to? First Fit answers "the earliest one that has room" — a greedy choice made without looking ahead.
The idea: scan left, grab the first fit
For each process, scan the blocks left to right. The moment you hit a block whose remaining size is >= the process size, assign the process there and stop scanning for that process. Then subtract the process size from that block so the next process sees the reduced space. If you reach the end of the blocks with no fit, the process is unallocated (-1).
The key insight: we commit on the first fit and shrink that block immediately. Because earlier processes can shrink a block below a later process's need, First Fit can leave a process unallocated even when the total free memory across all blocks would have been enough.
Walk through it
Step through the animation. The bottom row is the processes; the top row is the free blocks. The scan pointer sweeps the blocks left to right for each process. P0 (212) skips block 0 (100) and lands in block 1 (500 → 288). P1 (417) fits nowhere — even block 1 has shrunk to 288 — so it stays -1. P2 (112) takes block 1 again (288 → 176).
Pseudocode
alloc = [-1, -1, ...] # one slot per process, default "no fit"
for each process p with size:
for each block b from left to right:
if blocks[b] >= size: # first block large enough
alloc[p] = b
blocks[b] -= size # shrink the block we used
break # stop scanning for this process
return allocThe Python solution
def first_fit(blocks, processes):
alloc = [-1] * len(processes)
for p, size in enumerate(processes):
for b in range(len(blocks)):
if blocks[b] >= size:
alloc[p] = b
blocks[b] -= size
break
return allocallocstarts all-1, so any process that never finds a fit is already marked unallocated.- The outer loop walks the processes in order — First Fit respects the given process order.
- The inner loop scans blocks left to right, which is what makes it "first" fit rather than "best" fit.
if blocks[b] >= sizeis the greedy test: the first block with room wins.- After assigning,
blocks[b] -= sizeshrinks the block andbreakstops the inner scan so we never use a second block for the same process.
Complexity
| Case | Time | Notes |
|---|---|---|
| Per process | O(m) (moderate) | scan up to m blocks |
| All processes | O(n·m) (moderate) | n processes, m blocks |
O(n) (moderate)With n processes and m blocks the scan is O(n·m). The extra space is O(n) for the allocation array. First Fit is prized for being fast and simple — no sorting, no global search — at the cost of sometimes wasting space (a problem called external fragmentation).
When this pattern shows up
First Fit is the textbook example of a greedy allocation: commit to the first valid choice and never reconsider. The same shape appears in bin-packing, interval scheduling, and load assignment — any time you sweep candidates in a fixed order and grab the first one that satisfies a constraint.
Do not assume a process fits just because total free memory is enough. First Fit checks blocks
individually — blocks = [100, 200] cannot hold a process of 250 even though 300 is free in total. Also
remember to subtract after assigning, or later processes will see stale block sizes.
Practice
For blocks = [100, 500, 200] and process 417, after P0 (212) has taken block 1, which block does 417 land in?
1. What makes this strategy first fit rather than best fit?
2. Why might a process be unallocated even when total free memory exceeds its size?
3. Why do we break after assigning a process to a block?
4. What is the time complexity for n processes and m blocks?