在C中,我们可以分配内存automatically或dynamically:
size_t foo = 128;
char str1[64]; // Automatic
char str2[foo] // Automatic (variable-length, C99)
char *str3 = malloc(64); // Dynamic
char *str4 = malloc(foo); // Dynamic
使用自动分配,变量的作用域有限,并且通常在堆栈上分配内存,而动态分配使用堆。
让我们坚持使用字符串,说一个函数应该返回它以某种方式创建的字符串。似乎有两种常见的做法,都可以在标准库函数中看到:
malloc()
分配缓冲区并返回指向它的指针第一个优点是我们不需要记住free()
内存。另一方面,我们需要提供两个附加参数,并且需要以某种方式从外部确定缓冲区应具有的大小:
char str1[128]; // Let's hope this is large enough!
fill_my_buffer(str1, 128); // Might need more than 128, who knows
char *str2 = return_a_ptr(); // Just give me a pointer
size_t len = strlen(str2); // Ah, so that's what we got!
在C中自动或动态内存分配之间进行选择时应考虑哪些(其他)注意事项?
该问题基于观点而关闭,但我坚信对于这两种方法,都应该可以编制一份全面的目标利弊清单。
经验法则是,应避免在堆栈上分配“大”笔款项。一个页面(4096个字节)或两个页面是可以的,但是任何较大的页面都应该堆分配。
过多更改堆栈指针将破坏您的缓存性能,而缓存为王。
此外,您可能会溢出堆栈和保护页面miss,尽管这仅主要是线程的问题,这些线程必须具有有限的堆栈大小,或者在其他无法自动维护主线程的受限系统上线程堆栈增长。
除此之外,主要问题是语义:这个(小的)对象是否“属于”该堆栈框架,或者它需要生存不同的时间段(更长或更短)。
根本不需要担心需要调用free
,所有sorts函数都必须成对调用(这是C ++试图解决的主要问题,也是GNU的[ C0]扩展名),您应该养成始终知道这样做的纪律。
值得注意的是,takes指针的每个函数都应具有“谁负责此所有权”的概念?常见的所有权模型包括:借用的(由更高的堆栈框架拥有),唯一拥有的和共享的(通常是重新引用的)所有权,尽管可以存在许多微妙的变体(尽管并非同一程序中的所有变体)。
基本上是一个判断调用,调用代码可以知道缓冲区可能有多大吗?
调用者提供的缓冲区的复杂性是“当提供的空间不够大时该怎么办”。调用方提供的缓冲区的复杂性在于确保适当释放它,并确定如果内存分配失败该怎么办。