Malloc Lab
This project involved developing a dynamic memory allocator as part of the malloc lab, which required implementing the malloc, free, realloc, and calloc functions. The primary goal was to create an allocator that is both correct and efficient while maximizing throughput and utilization.
Abstract
This project involved developing a dynamic memory allocator as part of the malloc lab, which required implementing the malloc, free, realloc, and calloc functions. The development process included converting to an explicit-list allocator, implementing a segregated free list, and exploring techniques to minimize block size. Throughout the lab, various strategies were tested, including different block management designs and memory allocation techniques.
Commands to Execute
-mdriver -C
-checkpoint grade command: make submit -checkpoint
-mdriver-emulate
-mdriver-dbg
-./mdriver-dbg -f ./traces/syn-array-short.rep
Roadmap
Improving Throughput
Convert to an explicit-list allocator.
Convert to a segregated free list allocator.
These changes should not significantly affect utilization.
function to implement
a. coalesece_block()b. write mm_checkheap()
- check header alignment √
- check block loop case √
- try to print out header and footer/ to ensure they are consistent √
- check coalescing √
- check for epilogue and prologue blocks
find the footer
line670 asize = round_up(size + dsize, dsize);
dsize = 16 => footer is at the end of blockexplicit list
- design node struct: word_t* next, *prev; (use union to simplify code logics)
- implement insert_block(block_t *bp), remove_block(block_t *bp)
- set the minimum malloc size to 32 bytes (header, footer, next, prev).
- initialize with init_mm.
- call insert_block and remove_block during free and coalesce.
segregated list
- since a 16-byte block requires footer adjustments, start by implementing the segregated list with sizes of 32 bytes and larger.
- modify only the insert_block function.
- for 16B size block, we can utilize the last 3 or 4 bit, addr | bit
wrong: header and footer take 16B, if footer is resevered, no space for payload - the choice of first-fit or best-fit can make a significant difference in utilization.
checkpoint: use first-fit and final use best-fit
- eliminating footer
- alloc: set next block 1 << 1
free: unset next block 1 << 1 bit - decompose write_block() into write_block_alloc() and write_block_free()
- renew checkheap()
- update fucntion
alloc
free
find_fit
- alloc: set next block 1 << 1
Q&A
- no space for footer?
footer is only provided in spare blocks.
should i add a footer manually? No.
Final minimum block design
the most difficult part of this lab is Decrease the minimum block size.
1 | typedef struct mini_block { |
Other tricks to get full credits
- Since the allowed global memory is only 128 bytes, and 8 bytes are occupied by void *heap_start, 15 extra pointers are used to manage segregated lists. The block size for each list is somewhat tricky. Here is my final version of the block sizes for each list, where list_i stores blocks with sizes <= list_i and > list_i-1:
1 |
- Better fit algorithm is absolutely better.
Autograder output
Unused design
Reduce Headers Below 8 Bytes:
Set the header to be an int (4 bytes) for blocks where distance + block_size is smaller than max_int.
The highest 16 bits are never used in a VM with 16x addressing, so we can utilize themSpecial Memory Regions for Small, Fixed-Size Blocks:
Set up special regions of memory for small, fixed-size blocks.
This should theoretically improve utility, but I found that it only improved by 0.1%. It’s possible I forgot to free them completely when the tiny_block_pool is emptied.
1 | /** |
Lessons Learned
In this lab, i can try different types of design as i want. however, make a good design with as few bug as possible is not so easy. it takes me 3 or 4 days to finally settle down the final version of my mini_block. the last throwed design is struct {word_t header, word_t succ}, and i suppose to take use of an other link list to represent mini block. But there are several bugs and at that time it is hard to tell whether the bug lives in my link list or in my mini block. then i rollback to previous version and make my finally design. eventhough, i still meet some unforseen bugs as firstly a want to set length 16 in the header beside the last third bits. such behavior corrupt my succ pointer unexpectedly. after i throw length away, i finally pass without bugs. It is extremly essential to make a solid design before wrinting codes in such flexible tasks.
Before preceeding tasks, which will modify previous code or need to do some optimization, it is important to make my code consice and modole. if i modify my code repeatly, unfixed bugs accumulate and things become worse and worse when design become more and more complicated.
Unsure question
When make up a memory pool, what is the pre_alloc_state?
resolved, this block is strictly after a written block
Unfixed bug: when call extend_heap, we should write next block pre_alloc_state true
solution: call write_block_header() before write_block? line 1404
