假设我使用ptr = malloc(old_size);
来分配一个old_size
字节的内存块。只有第一个header_size
字节才有意义。我要将大小增加到new_size
。
new_size
大于old_size
且old_size
大于header_size
。
之前:
/- - - - - - - old_size - - - - - - - \
+===============+---------------------+
\-header_size-/
后:
/- - - - - - - - - - - - - - - new_size - - - - - - - - - - - - - - - - - - -\
+===============+------------------------------------------------------------+
\- header_size-/
我不关心ptr + header_size
之后存储的内容,因为我会在那里读取一些数据。
new_size
ptr = realloc(ptr, new_size);
header_size
并增长到new_size
ptr = realloc(ptr, header_size);
ptr = realloc(ptr, new_size);
header_size
字节void *newptr = malloc(new_size);
memcpy(newptr, ptr, header_size);
free(ptr);
ptr = newptr;
哪个更快?
答案 0 :(得分:3)
malloc
(对于整个块)和realloc
(对于增加大小时超出旧块大小的空间)都不保证您收到的内存将包含的内容,如果您需要那些多余的字节设置为零(例如),你必须自己做这样的事情:
// ptr contains current block.
void *saveptr = ptr;
ptr = realloc (ptr, new_size);
if (ptr == NULL) {
// do something intelligent like recover saveptr and exit.
}
memset (ptr + header_size, 0, new_size - header_size);
但是,既然你已经声明你不关心标题之外的内容,那么最快的几乎肯定是单realloc
,因为这可能会在封面下进行优化。
调用它两次进行收缩和扩展,或者调用malloc-new/memcpy/free-old
是不太可能有效率的,就像所有的优化一样,你应该测量,不要猜测!
请记住,realloc
根本不一定要复制你的记忆。如果扩展可以就地完成,那么智能堆管理器只会增加块的大小而不复制任何内容,例如:
+-----------+ ^ +-----------+ <- At same address,
| Old block | | Need | New block | no copying
| | | this | | involved.
+-----------+ | much | |
| Free | | now. | |
| | v +-----------+
| | | Free |
| | | |
+-----------+ +-----------+
答案 1 :(得分:2)
它几乎肯定取决于old_size
,new_size
和header_size
的值,而且还取决于实现。你必须选择一些值并进行衡量。
1)在header_size == old_size-1 && old_size == new_size-1
的情况下可能是最好的,因为它为您提供了单realloc
基本上是无操作的最佳机会。 (2)在这种情况下应该只是稍微慢一点(2几乎没有操作比1略慢)。
header_size == 1 && old_size == 1024*1024 && new_size == 2048*1024
的情况下, 3)可能是最好的,因为realloc
必须移动分配,但是你要避免复制你不关心的1MB数据。 (2)在这种情况下应该只是稍微慢一些。
header_size
比old_size
小得多时, 2)可能是最佳的,new_size
处于realloc
重新定位的合理可能范围内,但< em>也它很可能不会。那么你无法预测(1)和(3)中的哪一个会比(2)稍快一些。
在分析(2)时,我假设向下重新分配大约是空闲的并返回相同的指针。这不保证。我可以想到两件可能让你搞砸的事情:
其中任何一个都可能使(2)比(1)贵得多。所以这是一个实现细节,无论是否(2)是在(1)的优点(有时避免复制任何东西)和(3)的优点(有时避免复制太多)之间对冲你的赌注的好方法。
顺便说一下,这种关于性能的闲置猜测更有效,以便暂时解释你的观察结果,而不是试探性地预测我们会在不太可能发生的情况下做出什么样的观察,我们实际上已经足够关注性能来测试它。 / p>此外,我怀疑对于大型分配,通过将内存重新映射到新地址,实现可能甚至可以执行重定位realloc
而无需复制任何内容。在这种情况下,他们都会很快。不过,我没有考虑实现是否真的这样做。
答案 2 :(得分:1)
这可能取决于尺寸是多少以及是否需要复制。
方法1将复制旧块中包含的所有内容 - 但如果您不经常这样做,则不会注意到。
方法2只会复制您需要保留的内容,因为您事先会丢弃其他所有内容。
方法3将无条件地复制,而其他方法仅在内存块无法调整大小的情况下进行复制。
就个人而言,如果你经常这样做,我会更喜欢方法2,如果你做的更少,我更喜欢方法1。我将分析哪些内容会更快。