我很困惑,在分配内存时malloc
必须提供大小,但是,有时您不知道此时需要的大小,因此您要么分配大量内存(这听起来不太明智的,因为您可能不会全部使用它)或者您realloc
在初始缓冲区大小变得太小时时使用。这两个选项有效吗?第二个听起来不错,但是,文档说realloc
...may move the memory block to a new location
这听起来像是一个非常糟糕的主意/难以处理的情况(例如,如果您有多个指针指向同一个地址,那么当您调用realloc
它们时它们都变得无效)我是初学者使用 C,有人可以解释我如何处理您的缓冲区可能会或可能不会增长以占用大量内存的情况。
2 回答
有时您不知道此时需要的大小,因此您要么分配大量内存(这听起来不太明智,因为您可能不会全部使用它),或者您使用 realloc 什么时候初始缓冲区大小变得太小。这两个选项有效吗?
原则上是的。实际上,对于现代操作系统内核和默认系统配置,使用malloc分配多少并不重要。你看,malloc分配地址空间,而不是内存。您可以根据需要分配尽可能多的地址空间,它实际上不会消耗内存;当然,操作系统会对该值进行多次完整性检查,例如在只有 2GiB 可用内存(RAM + 交换)的系统上,您无法分配 3GiB。通常的配置是单个块中可分配的最大地址空间块是可用系统内存的 50%。
只有当您实际向其写入内容时,操作系统才会为它保留内存。所以不要使用calloc,因为它会初始化内存,即在其中写入一些东西。
因此,如果您不知道您究竟需要多少,只需 malloc 一大块地址空间,根据处理的数据类型的特征,您知道它很容易容纳您所期望的任何内容。一旦你把它放在内存中,你可以使用realloc来缩小分配。对于所有重要的实现,realloc在缩小分配时永远不会移动数据。
需要注意的一件事是内存过度使用:假设您有 5 个进程在具有 4GiB RAM 的系统上运行,每个进程分配 1GiB,但没有立即写入。操作系统会给他们这个地址空间,即它过度使用内存(就像航空公司过度使用航班座位一样)。一段时间后,进程开始写入它。在某些时候,系统内存不足,操作系统必须对此做点什么:它将开始杀死进程,直到再次有“呼吸”的空间。
不过,您可以关闭内存过度使用;强烈推荐用于高可靠性系统。
你是对的——这几乎是你的两个选择。您可以通过抽象一点来解决“多指针”问题。如果不是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;