new_size大于old_size,old_size大于header_size.
之前:
/- - - - - - - old_size - - - - - - - \ +===============+---------------------+ \-header_size-/
后:
/- - - - - - - - - - - - - - - new_size - - - - - - - - - - - - - - - - - - -\ +===============+------------------------------------------------------------+ \- header_size-/
我不关心在ptr header_size之后存储什么,因为我会读到一些数据.
方法1:直接进入new_size
ptr = realloc(ptr,new_size);
方法2:收缩到header_size并增长到new_size
ptr = realloc(ptr,header_size); ptr = realloc(ptr,new_size);
方法3:分配新的内存块并复制第一个header_size字节
void *newptr = malloc(new_size); memcpy(newptr,ptr,header_size); free(ptr); ptr = newptr;
哪个更快?
解决方法
1)最好是header_size == old_size-1&& old_size == new_size-1,因为它为您提供了单个realloc基本上是无操作的最佳机会. (2)在这种情况下应该只是稍微慢一些(2几乎没有操作比1轻微慢).
3)最好在header_size == 1&& old_size == 1024 * 1024&& new_size == 2048 * 1024,因为realloc必须移动分配,但是你要避免复制你不关心的1MB数据. (2)在这种情况下应该只是稍微慢一点.
2)当header_size远小于old_size时,可能是最好的,而new_size在realloc重新定位的合理可能范围内,但也很可能不会.那么你无法预测(1)和(3)中的哪一个会比(2)稍快一些.
在分析(2)时,我假设realloc向下大约是空闲的并返回相同的指针.这不保证.我可以想到两件可能让你烦恼的事情:
> realloc向下复制到新分配
> realloc向下拆分缓冲区以创建一个新的可用内存块,但是当你再次重新分配备份时,分配器不会再将新的空闲块直接合并到缓冲区中,以便在不复制的情况下返回.
其中任何一个都可能使(2)明显比(1)贵得多.所以这是一个实现细节,无论(2)是否是在(1)的优点(有时避免复制任何东西)和(3)的优点(有时避免复制太多)之间对冲你的赌注的好方法.
顺便说一句,这种关于性能的空闲猜测更有效,以便暂时解释你的观察,而不是暂时预测我们将在不太可能发生的事情中做出的观察,我们实际上已经足够关注性能来测试它.
此外,我怀疑对于大型分配,通过将内存重新映射到新地址,实现可能甚至可以执行重定位realloc而无需复制任何内容.在这种情况下,他们都会很快.不过,我还没有考虑实现是否真的这样做.