realloc()的性能消耗

Perfomance-consumption of realloc()

本文关键字:性能 realloc      更新时间:2023-10-16

我想知道realloc((实际需要多少性能:我经常这样做是为了将可用内存区域扩展一个元素(=特定结构(。多亏了MMU,这样的realloc((只是保留内存区域的扩展吗?还是在某些条件下可以完全复制所有数据?

据我所知,当std::vector的大小增加并且预定义的内存量太小时,它经常不得不复制内存区域。。。

realloc复制所有数据。假设其他任何事情都只是在要求性能问题。realloc可以避免复制的情况很少,绝对不应该指望它们。我见过不止一个realloc的实现,它甚至不需要实现代码来避免复制,因为这不值得付出努力。

MMU与此无关,因为重新映射支持分配的内存页面的成本直到达到两个以上页面才会得到回报。这是基于我15年前读到的研究,从那时起,内存复制变得更快,而由于MP系统,内存管理变得更加昂贵。这也适用于仅在内核内的零拷贝方案,而不传递系统调用开销,这是非常重要的,并且会降低速度。它还要求您的分配是完全一致的和适当的,这进一步降低了以这种方式实现realloc的有用性。

如果realloc将扩展到的内存块没有被分配,那么它最多可以避免复制数据。如果realloc是你的应用程序唯一能做的事情,你可能会很幸运,但只要有一点碎片或其他分配的东西,你就没有运气了。始终假设realloc是malloc(new_size); memcpy(new, old, old_size); free(old);

使用realloc调整数组大小时,一个好的做法是跟踪数组中有多少元素并具有单独的容量。只有当元素数量达到容量时,才增加容量和realloc。每个realloc的容量增加1.5倍(大多数人都会增加2倍,这在文献中经常被推荐,但研究表明,2倍会导致非常糟糕的内存碎片问题,而1.5倍几乎同样有效,对内存更好(。类似这样的东西:

if (a->sz == a->cap) {
    size_t ncap = a->cap ? a->cap + a->cap / 2 : INITIAL_CAP;
    void *n = realloc(a->a, ncap * sizeof(*a->a)); 
    if (n == NULL)
         deal_with_the_error();
    a->a = n;
    a->cap = ncap;
}
a->a[a->sz++] = new_element;

如果包含数组的结构是零初始化的,那么即使对于初始分配,这也有效。

复制数据并不是代价高昂的部分(尽管有些人可能不同意(。命中嵌入的mallocfree是昂贵的,并且可能会占用几乎所有的执行时间,这取决于您正在做的其他事情。如果是这样的话,修复它应该会给你一个大的加速。

这是我如何判断事物所花费的时间的分数。

最简单的解决方案是少做一次。当您分配一个数组时,请将其分配得特别大,然后自己跟踪实际使用了多少。

行为实际上取决于实现。但所有这些都试图将重新定位内存的成本降至最低。因为搬迁对性能来说非常昂贵。它对缓存有直接影响。我没有号码,但这是一项非常昂贵的手术
例如,在重新定位的情况下,如果运行时面临重新定位内存或扩展当前保留的内存的两个选项,则选择后者
但事情并不像我说的那么简单。它还必须考虑内存碎片
因此,有几个权衡需要满足
在您提到的vector的情况下,它们使用不同的方案。如果vector保留了m字节,并且它需要额外的n字节,则运行时将分配2 * (n+m)以最大限度地减少将来重新定位的可能性。如果您超过了新的大小,下次它将使用4而不是2的因子;等等。我提到的数字不是真的
我对实现不是很感兴趣,希望其他人能给你更多具体的信息。