选择缓冲区的大小

8

我有些困惑,使用 malloc 分配内存时需要提供一个大小,但有时你不知道此时需要多大的空间,所以你要么分配大量的内存(这听起来并不明智,因为你可能不会全部使用),要么在初始缓冲区大小变得太小时使用 realloc。这两种选择都是有效的吗?第二种听起来不错,但文档说 realloc 可能会将内存块移动到新位置,这听起来像一个非常糟糕/难以处理的情况(例如,如果你有多个指针指向同一地址,在调用 realloc 时它们都将无效)。作为一个 C 初学者,有人可以解释一下如何处理可能或可能不会增长以占用大量内存的缓冲区的情况吗?


4
如果您有多个指针指向同一地址,那么是的,当将realloc()返回的新指针分配给原始指针变量时,您需要更新所有指针。这并不难做到。但是,需要更新太多指向相同地址的指针似乎是一个糟糕的设计。 - P.P
2
在编程中,使用 stdio.h 中的 BUFSIZ 宏并在空间不足时复制它是常见的方法。 - Adrián
此外,一些平台相关的丑陋技巧包括使用 malloc_size() 等。 - user529758
2个回答

5
有时您可能不知道需要多大的空间,因此您要么分配大量内存(这听起来并不明智,因为您可能不会全部使用),要么在初始缓冲区大小变得太小时使用realloc。 这两个选项是否有效?原则上是的。 实际上,在现代操作系统内核和默认系统配置下,无论您使用malloc分配多少内存都没有关系。你看,malloc分配地址空间而不是内存。 您可以分配任意数量的地址空间,它不会实际占用内存; 当然,操作系统将对该值进行几个健全性检查,例如在仅有2GiB可用内存(RAM +交换)的系统上,您无法分配3GiB。通常的配置是单个块中可分配的最大地址空间块为可用系统内存的50%。只有当您实际写入内容时,操作系统才会为其保留内存。 因此,请勿使用calloc,因为它使用初始化内存,即将一些东西写入其中。因此,如果您不知道需要多少空间,请先分配一个大的地址空间块,根据所处理数据类型的特征,您知道它将轻松容纳您预期的任何内容。 将其放入内存后,您可以使用realloc来缩小分配。 对于所有相关实现,当收缩分配时,realloc永远不会移动数据。 请注意内存超额承诺:假设您在具有4GiB RAM的系统上运行5个进程,每个进程分配1GiB,但不立即写入它。 操作系统将为它们提供这个地址空间,也就是说,它过度承诺了内存(就像航空公司过度承诺了飞行座位一样)。 一段时间后,进程开始将其写入。 在某个时刻,系统用尽了内存,操作系统必须采取措施:它将开始终止进程,直到再次有“呼吸”空间。但是,您可以关闭内存超额承诺;如果要求高可靠性,则强烈推荐这样做。

非常有趣的答案,但是如果你按顺序写入数据,那么一旦你写入第一个片段,整个缓冲区就会被分配。所以你不会获得太多好处。只有当你一次性写入数据时才能获得好处。无论如何,关于calloc/malloc的观点已经被接受,谢谢。 - Meda
2
@Meda,而不是整个缓冲区。如果我malloc 1M的内存,并触摸第一个字节,系统将提交一页内存(传统上为4k,但在现代系统中可能更大),而不是整个范围。 - Sean Conner
好的,我想这是最好的方法(malloc一个巨大的值并不用担心,因为任何现代内核都会使用你所描述的分页技术来很好地处理它)。我觉得我应该改变我的采纳答案,并将其更改为进一步证据出现之前。 - Meda

3

您说得对 - 这基本上是您的两个选择。您可以通过抽象化来解决“多指针”问题。如果您不直接传递 malloc 返回的指针,而是将其放入另一个数据结构中:

struct malloc_wrapper
{
    void *p;
} wrapper;

wrapper.p = malloc(INITIAL_SIZE);

而是传递指向该数据结构的指针,您可以随时更改 p,并且共享指针的任何人都会相应地更新到您的新结构:

void *tmp = realloc(somepointertowrapper->p, NEW_SIZE);

/* check tmp to ensure it's not NULL. That indicates a failure
 * to realloc and the original pointer passed into realloc 
 * remains valid.
 */

somepointertowrapper->p = tmp;

在将 realloc 的结果分配给指针以检测分配失败之前,始终检查其结果。请记住,realloc 是一个可怕的接口,因为它试图成为所有人的一切。我不是在开玩笑:您可以避免使用 mallocfree 并使用 realloc任何事情 - Nik Bougalis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接