C:是提前分配内存还是按需分配内存?

C:是提前分配内存还是按需分配内存?,c,C,我有一个很简单的问题要问你。在C中创建自己的动态数组实现时,当数组接近其当前最大容量时,是提前分配内存(假设为10个元素)更好,还是每次元素计数改变时分配realloc内存更好 我的意思是:为了性能、优雅或任何你想到的东西。尽可能少地使用性能会更好。因此,您可以执行以下操作: array=realloc(数组,旧大小*2)通常的选择是将当前大小乘以一个大于1的固定数字(通常为1.5ish,如2),这将使您分摊总分配和复制成本 请注意,不能保证您可以在适当的位置增加数组的大小,因此您可能必须将所有

我有一个很简单的问题要问你。在C中创建自己的动态数组实现时,当数组接近其当前最大容量时,是提前分配内存(假设为10个元素)更好,还是每次元素计数改变时分配realloc内存更好


我的意思是:为了性能、优雅或任何你想到的东西。

尽可能少地使用性能会更好。因此,您可以执行以下操作:


array=realloc(数组,旧大小*2)

通常的选择是将当前大小乘以一个大于1的固定数字(通常为1.5ish,如2),这将使您分摊总分配和复制成本


请注意,不能保证您可以在适当的位置增加数组的大小,因此您可能必须将所有现有元素复制到新位置(
realloc()
自动为您执行此操作,但您仍然需要支付成本)。

在堆上分配内存的成本总是很高的。一个元素一个元素地进行操作根本不可取。

您可以定义如下结构:

/** Dynamic array */
typedef struct __darray {
        int* array;            /** Array */
        int size;               /** Array size */
        int cap;                /** Capacity */
} darray;
容量大小。 如果为true,则执行内存重新分配。 公式(取自JDK的ArrayList实现)为:


如果从动态数组中删除(足够多)元素,不要忘记再次收缩“int*”

如果此动态数组实现打算在许多上下文中使用,那么最好将预测性额外分配的控制权交给用户,而不是将其嵌入库中。

Solaris和Linux采用了一种较新的内存分配策略。还使用了如所述的板分配器。

通常最好以“起始”固定大小进行预分配,并在空间不足时根据增长因子进行重新分配

根据您的需要,可以根据您正在处理的数据的典型使用情况确定起始大小和增长因子,或者您为数据创建的API允许调用方在初始化/创建调用中指定起始大小和增长因子

起始尺寸应为基于典型用途的数字。典型用途是帮助您选择尺寸的重要因素,以便您:a)不要选择“太大”的起始尺寸浪费空间,B)不要使用太小的起始尺寸,直到达到目标典型尺寸,否则需要进行多次重新分配

当然,典型的尺寸是一个神奇的数字。确定典型大小的一种方法是使用各种数据集运行一些测试,并收集数据的起始大小、重新分配的数量和最小/最大内存使用量的统计信息。您可以对结果进行平均,以获得可用的典型起始大小

至于生长因子,x1.5或x2生长因子是常见的。这是您可以使用测试统计数据和起始大小来衡量的


另一个要考虑的是,需要对动态可调整数据的引用进行管理,因为RealLoad()将在需要时将数据重新定位到内存中。这意味着,如果存储了可动态调整大小的数组的第一个元素的地址,则调用realloc后该地址可能无效。这可以通过围绕自定义数据类型的API包装来管理,该包装提供索引而不是内存地址,并且在需要时可以将索引解析为元素的当前地址。

不要忘记更改旧大小的值!数组=realloc(数组,旧大小=(旧大小*2));如果您知道阵列的平均大小和增长率,也可以对此进行优化。不要忘记,
realloc
可能会失败!在进行乘法之前,您需要检查溢出:
if(old_size>size_MAX/2){handle_error();}
小错误,但是。。。如果您从oldsize=0(无数据)开始,那么您真的应该这样做((oldsize+1)*2)或max(1,oldsize*2),否则您将永远被大小为零所困扰。此外,许多小的分配可能会分割堆这对于动态数组实现来说似乎是一个糟糕的选择。我同意,但是在学习Solaris内部构件时发现了解它非常有趣。
(jobs here...)
[your_darray]->capacity+=[your_darray]->capacity*3/2+1;
[your_darray]->array=(int*)realloc([your_darray]->array,capacity*sizeof(int));
(jobs here...)