在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()
将缓冲区写入到提供的buffer
第一种方法的优点是我们不需要记住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中选择自动或动态内存分配时,应该考虑哪些(其他)考虑因素?
这个问题是以意见为基础的,但我相信应该可以为这两种方法编制一个客观利弊的综合列表,这样就可以在个案的基础上做出明智的决定。
发布于 2018-06-04 00:15:17
一条经验法则是,您应该避免在堆栈上进行“大”分配。一两个页面(4096字节)就可以了,但是任何更大的页面都应该是堆分配的。
改变堆栈指针太多会降低缓存性能,缓存才是王道。
此外,您可能会溢出堆栈并错过保护页,尽管这主要是必须具有有限大小堆栈的线程的问题,或者在其他受限制的系统上不能自动主线程堆栈增长的问题。
除此之外,主要的问题是语义:这个(小)对象是否“属于”这个堆栈框架,或者它是否需要存在一段不同的时间(更长或更短)。
调用free
的需求根本不应该是一个问题,有各种各样的函数总是必须成对调用的(这是C++试图解决的主要问题,也是GNU的__attribute__((cleanup))
扩展),你应该养成总是知道去做的原则。
值得注意的是,每个接受指针的函数都应该有一个“谁负责这个所有权”的概念。常见的所有权模型包括:借用(由一些更高的堆栈框架拥有)、唯一拥有和共享(通常重新计算)所有权,尽管可能有几十种微妙的变体(尽管不是所有的都在同一个程序中)。
发布于 2018-06-03 23:03:38
这基本上是一个判断调用-调用代码能知道缓冲区可能有多大吗?
调用者提供的缓冲区的复杂之处在于“当提供的空间不够大时该怎么办”。调用者提供的缓冲区的复杂之处在于确保它被适当地释放,并决定在内存分配失败时如何处理。
https://stackoverflow.com/questions/50667681
复制相似问题