The following problem concerns dynamic storage allocation.
Consider an allocator that uses an implicit free list.
The layout of each allocated and free memory block is as
follows:
31 2 1 0
__________________________________
Header | Block Size (bytes) | |
|____________________________|_____|
| |
| |
| |
| |
| |
|__________________________________|
Footer | Block Size (bytes) | |
|____________________________|_____|
Each memory block, either allocated or free, has a size that
is a multiple of eight bytes. Thus, only the 29 higher order
bits in the header and footer are needed to record block
size, which includes the header and footer. The usage of
the remaining 3 lower order bits is as follows:
-
bit 0 indicates the use of the current block: 1 for
allocated, 0 for free.
- bit 1 indicates the use of the previous adjacent
block: 1 for allocated, 0 for free.
- bit 2 indicates the use of the next adjacent
block: 1 for allocated, 0 for free.
Given the contents of the heap shown on the left, show the
new contents of the heap (in the right table) after a call
to free(0x600a010) is executed. Your answers should
be
given as hex values. Note that the address grows from bottom
up. Assume that the allocator uses immediate coalescing,
that is, adjacent free blocks are merged immediately each
time a block is freed.
Address |
|
0x600a028 |
0x00000016 |
0x600a024 |
0x600b611c |
0x600a020 |
0x600b512c |
0x600a01c |
0x00000016 |
0x600a018 |
0x00000011 |
0x600a014 |
0x600b511c |
0x600a010 |
0x600b601c |
0x600a00c |
0x00000011 |
0x600a008 |
0x00000016 |
0x600a004 |
0x600b601c |
0x600a000 |
0x600b511c |
0x6009ffc |
0x00000016 |
void * coalesce(void * bp);
param: bp - Points to a free block; not on the linked list (or
tree) of free blocks.
Description: Removes adjacent blocks from the free list (or
tree) if either one or both are free. Merges block bp
with these free adjacent blocks.
Return: pointer to the merged block; also this block is NOT yet
in the linked list or tree of free blocks.
void * extend_heap(size_t nwords)
param: nwords - number of 4 byte words
Description: Allocates a new free block of size which is a
multiple of 8 immediately after the last block. Merges
this new block with the last block if that block is free.
Rewrites an eiplog block after the new block.
Return: pointer to the new free block (NOT yet in the linked
list or tree of free blocks)
void mm_insert(void *bp)
param: bp - pointer to a block that is already marked free.
Description: adds this block to the free list (or the tree) of
free blocks
void mm_remove(void *bp)
param: bp - pointer to a block that is on the linked list
(or in the tree) of free blocks.
Description: removes this block from the linked list (or the tree) of
free blocks
void *bp mm_findMax(void *bp)
param: bp - pointer to a block that is in the tree of
free blocks
Description: finds the block with the largest size in the
subtree with root bp.
Return: A pointer to the block with the largest size
void *bp mm_ceiling(void *bp, size_t asize)
param: bp - pointer to a block that is in the tree of
free blocks
Description: finds and returns the block in the subtree
at bp with the smallest size that is >= asize. If no such
block exists, return NULL.
Return: A pointer to a block with the smallest size that
is >= asize. If no such block exists, returns NULL.
int mm_init(void)
Description: Initializes the heap:
(1) Allocates space for: padding, prolog, and epilog
(2) Initializes the header, footer of the prolog
(3) Initializes the header of the epilog
(4) Sets the global pointer to the prolog (payload
portion)
(5) Allocates a free block of size CHUNKSIZE words by
calling extend_ heap
(6) Inserts the free block returned from extendheap into
the linked list (or tree) of free blocks.
Return: 0 for success or -1 if the initial free block
cannnot be allocated by extend_heap
void * find_fit(size_t asize)
param: asize - the adjusted size (includes header and
footer) of a free block that is requested.
Description: Search through the linked list (or tree) of
free blocks for a free block whose size is >= asize (the
requested size). Remove this block from the linked list
(or tree) and return it. If no such block is found,
return NULL.
With the linked list, the search could use first fit or
next fit. Other searches (such as best fit) are
likely to take longer and impact the throughput.
With a binary search tree, search for the 'ceiling' - a free
block whose size is the smallest size that is still >= asize.
So this will implement best fit. The binary tree should
permit faster searches and so provide acceptable
throughput.
Return: A free block (not on the linked list or tree of
free blocks) whose size is >= the requested size, asize.
void * place(void *bp, size_t asize)
param: bp - pointer to a free block, not on the linked
list or in the tree of free blocks whose size is >= asize
param: asize - the requested size of a free block
Description: Determines if the block bp has size big
enough to split into a block of the requested size and
a free block. In order to split, the extra size >
asize must be big enough to hold the header, footer, a
non-empty payload and must have total size that is a
multiple of the alignment (8).
If the block is split, the allocated part is marked
allocated and the free part is marked free and
the free part must be inserted into the linked list (or tree)
of free blocks.
If the block is not split, it is simply marked allocated.
Suggested Optimization: If the block is to be
split, the allocated part should be taken from the
'small' end of the block if the requested block is
'small'; otherwise, it should be taken from the 'big' end.
Return: A pointer to the allocated block.
void * mm_malloc(size_t size)
param: size - The requested size (payload only) of a block
Description: Calculate the adjusted size, asize, to
include the header and footer and round up if necessary to
satisfy the alignment requirement (e.g. total size must be a
multiple of 8).
Then
(1) call find_fit to get a free block of size >= asize
that has been removed from the linked list (or tree) of
free blocks
(2) if no block found call extend_heap to get a free block
(3) if extend_heap can't extend the heap return NULL
(4) otherwise call place with the free block and the
requested size, asize to possibly split the block and to
mark the selected block as allocated.
(5) return the allocated block that is returned by place
Return: the allocated block or return NULL if no block could be
found and the heap could not be extended.
void mm_free(void *bp)
param: bp - pointer to a block that was previously
allocated
Description: Marks this block as free. Calls coalesce to
merge with adjacent free blocks if any, then inserts the
returned (possibly larger) free block into the linked
list (or tree) of free blocks.
void * mm_realloc(void *bp, size_t newsize)
param: bp - A pointer to an allocated block (that may
already have user data in the payload)
param: newsize - A new size requested
Description:
Special cases:
(1) if newsize is 0, call mm_free(bp) and return NULL
(2) if bp is NULL, call and return mm_malloc(bp)
Otherwise: Return a block of size >= newsize that preserves
all the data from the payload of the block bp.
Suggested Optimizations:
(1) If newsize <= current size of bp, just return bp
(2) If the next block after bp is free and its size plus the
size of bp is >= the requested newsize, remove the free
block, rewrite the header and then the footer of bp to change
the size of bp and return bp.
(3) If the next block after bp is free, but its size plus the
size of bp is NOT >= the requested newsize, BUT this next
block is the 'last' block (before the epilog), call
extend_heap to get additional size and rewrite the header and
then the footer of bp to change the size of bp. Return bp.
(4) If bp is the 'last' block (before the epilog), call
extend_heap to get additional size and rewrite the header and
then the footer of bp to change the size of bp. Return bp.
If none of these optimizations apply, use mm_malloc to get a new
block, the C library function memcpy to copy the payload to the
new block, mm_free block to free bp and return the new block.
Return: A pointer to the new sized block (with the
preserved data) or NULL if no such block could be produced.