假设我已经使用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
因为我会读一些数据到那里。
方法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;
哪个更快?
几乎可以肯定取决于值old_size
, new_size
和header_size
,并且还依赖于实现。 你必须挑选一些价值观和衡量。
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),I已经假设realloc的向下近似自由并返回相同的指针。 这不能保证。 我能想到的两件事情,可以把你弄得一团糟:
- realloc的向下复制到新的分配
- realloc的向下拆分缓冲创建的免费存储新块,但是当你realloc的备份再分配器不会合并新的空闲块直背到您的缓冲区又为了不复制返回。
无论是那些可以使(2)除(1)显著更加昂贵。 所以这是一个实现细节是否(2)的优点与对冲你的赌注的好方法(1)(有时也避免了复制任何东西)和(3)的优点(有时是避免复制太多)。
顺便说一句,这种对性能游资炒作更为有效,以初步解释你的观察,是不是比初步预测什么意见,我们会作出,我们实际上关心不够有关性能进行测试万一。
此外,我怀疑,对于大的分配,实现可能能够做到即使是搬迁realloc
没有任何复制,通过重新映射存储到一个新的地址。 在这种情况下,他们都将是快。 我还没有研究是否实现真正做到,虽然。
无论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将只复制你需要什么,以保持,因为你放弃一切事前。
方法3将无条件复制,而如果内存块不能调整大小的地方是别人只拷贝。
就个人而言,我想如果你这样做往往如果你这样做更很少喜欢的方法2,或方法1。 分别,我会分析哪些,这些会更快。