mem_init
中可以看出整个分配器是在一大段已经分配好的连续的内存中进行的mem_sbrk
进行扩展时也是连续扩展,模拟堆的向上增长malloc
也是八字节对齐,所以可以满足强制八字节对齐的要求traces
测试用例来测试理解逻辑后,接下来将实现自己的版本
typedef unsigned long word;
typedef char byte;
// mark the front and tail pos
void *front_p = NULL;
void *tail_p = NULL;
bp == front_p
则 PREV(bp)
内的值无效,tail_p
同理size
均应在传入之前对齐,均不包含头尾部大小#debug
对于 segmentation fault
使用 gdb
获取头尾块的 size
发现尾部异常值 0xcdcdcd
,在代码中使用 print
跟踪 trail_p
变量,发现在__coalesce_next
处没有及时更新#bug1
若记录的 size
是有效载荷的 size
,合并和分割时应注意增减 DSIZE
#bug2
每次合并都需要判断 tail_p
是否改变,特别是 __coalesce_next
的情况Results for mm malloc:
trace valid util ops secs Kops
0 yes 99% 5694 0.007579 751
1 yes 100% 5848 0.006639 881
2 yes 99% 6648 0.010560 630
3 yes 100% 5380 0.008016 671
4 yes 100% 14400 0.000102140762
5 yes 92% 4800 0.006677 719
6 yes 92% 4800 0.005988 802
7 yes 55% 12000 0.141468 85
8 yes 51% 24000 0.274197 88
9 yes 33% 14401 0.128358 112
10 yes 50% 14401 0.002138 6734
Total 79% 112372 0.591722 190
Perf index = 47 (util) + 13 (thru) = 60/100
realloc
的优化 v1new_size <= old_size
则不分配而是切割new_size
则合并realloc
的优化 v2realloc
的优化 v3realloc
/**
* implemented simply in terms of mm_malloc and mm_free
* compare adjust_size and total_size step by step
*/
void *mm_realloc(void *ptr, size_t size) {
if (ptr == NULL) return mm_malloc(size);
if (size == 0) return NULL;
void *new_ptr;
size_t adjust_size = ALIGN(size);
size_t old_size = SIZE(ptr);
if (adjust_size <= old_size) {
// just return, for the memory lost is little
return ptr;
}
size_t next_size = (ptr != tail_p && !ALLOC(NEXT(ptr))) ? SIZE(NEXT(ptr)) + DSIZE : 0;
size_t total_size = old_size + next_size;
if (adjust_size <= total_size) {
__coalesce_next(ptr);
_place(ptr, adjust_size); // just cut
return ptr;
}
size_t prev_size = (ptr != front_p && !ALLOC(PREV(ptr))) ? SIZE(PREV(ptr)) + DSIZE : 0;
total_size += prev_size;
if (adjust_size <= total_size) { // coalesce prev or all
new_ptr = _coalesce(ptr);
memmove(new_ptr, ptr, old_size);
_place(new_ptr, adjust_size);
} else {
if ((new_ptr = mm_malloc(size)) == NULL) return NULL;
memmove(new_ptr, ptr, old_size);
mm_free(ptr);
}
return new_ptr;
}
Results for mm malloc:
trace valid util ops secs Kops
0 yes 99% 5694 0.007401 769
1 yes 100% 5848 0.006883 850
2 yes 99% 6648 0.011138 597
3 yes 100% 5380 0.008327 646
4 yes 100% 14400 0.000092156013
5 yes 92% 4800 0.006244 769
6 yes 92% 4800 0.005888 815
7 yes 55% 12000 0.142196 84
8 yes 51% 24000 0.277304 87
9 yes 50% 14401 0.018129 794
10 yes 86% 14401 0.000132108933
Total 84% 112372 0.483734 232
Perf index = 50 (util) + 15 (thru) = 66/100
next fit
fitted_p
并且需要在多处维护:初始化,分配,合并best fit
next_fit
会降低内存利用率,而 best_fit
会降低吞吐率,但我们可以进行一个折衷,即在 fitted_p
后部分首次适配,而在 fitted_p
前部分最佳适配_next_fit
Results for mm malloc:
trace valid util ops secs Kops
0 yes 91% 5694 0.001803 3158
1 yes 92% 5848 0.001315 4446
2 yes 97% 6648 0.003706 1794
3 yes 97% 5380 0.003602 1494
4 yes 100% 14400 0.000085169213
5 yes 91% 4800 0.004207 1141
6 yes 90% 4800 0.003837 1251
7 yes 55% 12000 0.057487 209
8 yes 51% 24000 0.029497 814
9 yes 50% 14401 0.054370 265
10 yes 70% 14401 0.000116124684
Total 80% 112372 0.160025 702
Perf index = 48 (util) + 40 (thru) = 88/100
sizeof(unsigned long)
,同时还需定义最小的空闲块大小list_p
标记头部
_coalesce
之前都会产生一个未入链表的空闲块,我们只需要修改 __coalesce_next, __coalesce_all
,以及没有合并的情况,并将 list_p
指向新块_place
时都需要维护链表,存在没有空闲链表的情况,这时让 list_p
为空realloc
的优化,由于会调用 _coalesce, _place
,可能会把原始信息破坏,或覆盖链表信息,需要修改为仅合并后部分空闲链表,并且合并部分需重写_fix_list
实现替换的逻辑,还需要注意加入链表(__coalesce_none
),移除链表(_place
)的情况_check
函数用以查看遍历空闲链表获得的空闲块数和遍历整个链表获取的空闲块数是否相同,以此判断链表是否正确,并用 debug
宏标注,编译选项中加入 -DDEBUG
才会输出信息_check
的信息,我们将错误定位在 __coalesce_none
处,发现在空闲块存在而没有合并时应写插入的逻辑,而 _fix_list
写的是替换的逻辑bug
后,我们的链表总算是维护好了,但是分数也降到了 80 分,接下来让我们实现显示链表的适配版本 _first_fit_of_clear
debug
没有白费Results for mm malloc:
trace valid util ops secs Kops
0 yes 90% 5694 0.000211 26960
1 yes 91% 5848 0.000128 45581
2 yes 95% 6648 0.000217 30636
3 yes 98% 5380 0.000135 39911
4 yes 100% 14400 0.000090159645
5 yes 90% 4800 0.000457 10503
6 yes 87% 4800 0.000453 10587
7 yes 55% 12000 0.003927 3056
8 yes 51% 24000 0.002370 10127
9 yes 41% 14401 0.000422 34126
10 yes 86% 14401 0.000087166486
Total 80% 112372 0.008497 13225
Perf index = 48 (util) + 40 (thru) = 88/100
@deprecated
标记2022.12.29 ~ 2022.12.31