我的应用程序有一个main
函数,例如,我为配置文件等分配路径。目前我为它们使用malloc
,但它们从未被释放,并且在应用程序的整个生命周期中始终可用。我甚至从来没有释放过它们,因为当应用程序终止时,操作系统已经自动回收分配的内存。在这一点上,有没有理由不使用alloca
而不是malloc,因为程序在main
返回时结束,而alloca
内存只有在分配给它的函数释放后才会被删除。因此,基于此逻辑,只有在程序结束时(这是所需的),才释放在具有alloca
的主函数中分配的内存。这些语句正确吗?有没有理由不在main
中使用alloca
(alloca是一种糟糕的做法,所以当我说alloca意味着alloca或在main
中生成VLA时),用于持续到程序终止的类似"全局VLA"的对象?
您可以在main中使用alloca/VLA,但为什么?
使用它们的典型原因是,如果您有一些性能敏感的部分被调用了很多,并且您不想要malloc/free的开销。对于main,在程序开始时只分配一次数据,因此几个malloc调用的开销可以忽略不计。
主要不使用alloca/VLA的另一个原因是它们消耗堆栈空间,与堆空间相比,堆栈空间是非常有限的资源。
取决于您需要多少内存。如果它足够小(比如几百字节左右),您可以安全地在main()
中执行alloca
或使用VLA。
但是,如果这些数组的大小有一个已知的上限,这个上限不是很大,那么用这个上限作为大小全局声明它们会更好、更安全。这样就不会占用堆栈空间,也不必malloc
然后确保分配成功。无论是谁在阅读,都清楚地知道,这段记忆的寿命与程序的寿命一样长。
如果大小可以任意大,那么最好的做法就是像现在一样继续使用malloc()
。顺便说一句,即使您在main()
中调用malloc()
并在程序的整个生命周期中使用它,在退出之前释放它仍然是一种很好的做法。
技术上没有,因为函数中声明的任何变量都不是全局的。但你可以这样做:
char *buffer;
int main(void) {
char buf[size];
buffer = buf;
这将为您提供一个全局访问缓冲区的接口。
在这一点上,有没有理由不使用alloca而不是malloc
这是一个通常应该反过来问的问题。是否有理由使用alloca
而不是malloc
?如果您有性能问题,可以考虑更改,但如果您只是想避免使用free
,我认为这是一个糟糕的原因。
但我真的不明白这有什么意义。如果你有一个分配的缓冲区,你想从程序开始到结束,那么只需在主函数结束时释放它。
int main(void) {
char *buf = malloc(size);
// Do work
free(buf);
}
我写了一个关于alloca
和VLA:s的长答案,你可能会觉得有用。我真的需要malloc吗?
VLA(由标准定义)和非标准alloca
都用于在本地范围内分配临时小数组。没有别的。
在堆栈上分配大对象是微妙&严重的堆栈溢出错误。这就是您应该避免大型VLA和alloca
对象的原因。每当您在文件范围内需要大型对象时,它们应该是static
数组或使用malloc
动态分配。
需要注意的是,堆栈分配通常比堆分配快,因为堆栈分配不需要关心查找、碎片和其他特定于堆实现的问题。堆栈分配只是说";这100个字节是我的";然后你就可以出发了。
关于";栈对堆";请参阅堆栈和堆上分配了什么?
您甚至不能在文件范围中放置标准的VLA,因为数组大小需要是一个整数常量表达式。此外,标准(C17 6.7.6)明确规定不允许:
如果标识符被声明为具有静态或线程存储的对象持续时间,它不应具有可变长度的数组类型。
至于alloca
,它不是标准的C,因此很糟糕。但它也很糟糕,因为它没有任何类型的安全性,所以VLA比alloca
更受欢迎——它更安全、更便携。
应该注意的是,VLA在现代编程中的主要目的是启用指向VLA的指针,而不是分配VLA类型的数组对象,这是一个使用有限的特性。
我甚至从未释放它们,因为当应用程序终止时,操作系统已经自动回收分配的内存。
虽然这是正确的,但手动调用free()仍然被认为是一种很好的做法。因为如果程序中有任何堆损坏或指针相关的错误,调用free()时就会崩溃。这是一件好事,因为它允许您在开发的早期发现此类(常见)错误。
(如果你关心free()的性能,你可以从发布版本中排除free(()调用,只在调试版本中使用它们。尽管关闭程序时性能很少是个问题——通常你可以关闭GUI(如果有的话),然后让程序在后台慢慢清理代码。)