Memory Management
The issues in memory requests:
- fixed or varying length records or mixed
- small or large records
- do we care more about response time efficiency or space usage
efficiency?
- does the system use explicit or implicit freeing technique?
The goals we want to achieve in memory management:
- allocate blocks in required sizes
- keep unused memory spaces as large as possible
- combine memory spaces when they are freed
Cost Criteria:
- memory utilization (avoid unusable space)
- memory usage overhead (for management structures)
- allocation time efficiency (response to allocation requests quickly)
Implicitly freeing memory space (garbage collection)
- Reference counts:
The reference count is incremented for each new reference,
and is decremented if a reference is overwritten, or if
the referring object is recycled. If a reference count falls
to zero, then the object is no longer required and can be recycled.
The main problems with simple refernce counting:
- The reference count field usually has to have limited size,
and the system therefore breaks down if the number of possible
references to an object is unbounded.
- Reference counting involves an operation on every
modification of a pointer, which increases code size, increases
demand for memory bandwidth, decreases locality of reference
and can be a serious performance penalty (especially in
multi-threaded environments where refernce count updates
require synchronization).
- Every object needs to be slightly larger in order to store
the reference count.
- If any objects are part of a cyclic data structure, then
they will always have a non-zero reference count, and hence
won't be reclaimed when they are dead.
- Mark and sweep:
The mark phase follows reference chains to mark all reachable
objects; the sweep phase performs a sequential (address-order)
pass over memory to recycle all unmarked objects.
The mark phase can be done as a depth first search to identify
all live objects (objects in use). And the sweep phase put
unreachable (dead) objects to free list.
- Mark and compaction:
Marking all reachable objects, then compacting the marked objects.
The compaction phase typically performs a number of sequential
passes over memory to move marked (live) objects and update
references.
As a result of compaction, all the marked objects are moved
into a single contiguous block of memory (or a small number
of such blocks); the memory left unused after compaction
is recycled.
This method can eliminate internal fragmentation, thus make
large free blocks available for more efficient allocation
mechanisms. However, it is quite expensive to copy large blocks
used by live objects.
Explicitly freeing memory space has two operations explicitly called
by applications: allocate (new/malloc/calloc) and free (delete/free).
Utilization of memory space can't be perfect -- it's an NP complete
problem. The heuristics commonly used for allocation includes:
- Best Fit: allocate from the smallest block that satisfies the request
- Worst Fit: always allocate from the largest block (so that
a bigger chunk may be left for later use hopefully)
- First Fit: allocate from the fist block that satisfies the request;
it is usually as good as best fit.
- allocate from the most recently freed block that satisfies the request
Example memory management methods:
- The Boundary-Tag method:
The free blocks are doubly circularly linked. The worst case
allocation cost is to search the entire list to find a fit.
The freeing cost is constant.
- Buddy System:
There is an array of free lists, one for each allowable block size.
Allocation rounds up the requested size to an allowable size and
allocates from the corresponding free list. If the free list is empty,
a larger block is selected and splitted to two equal sized buddies.
A block may only be combined with its buddy, and this is only
possible if the buddy has not been splitted into smaller blocks.
The advantage of buddy system is that the buddy of a block being
freed can be quickly found by a simple address computation.
The disadvantage of buddy system is that the restricted set of
block sizes leads to high internal fragmentation, as does
the limited ability to combine the freed blocks.