2

我的应用程序有一个main功能,例如,我分配了配置文件的路径等。目前我malloc用于它们,但它们从未被释放并且在应用程序的整个生命周期中始终可用。我什至从未释放它们,因为当应用程序终止时操作系统已经自动回收分配的内存。此时,是否有任何理由不使用allocamalloc 代替,因为程序在main返回时结束,并且alloca只有在释放分配它的函数后才会删除内存。所以基于这个逻辑,在主函数中分配的内存alloca只有在程序结束时才被释放,这是所需的。这些陈述是否正确,是否有任何理由不使用allocaalloca 是不好的做法所以当我说 alloca 的意思是 allocamain在) 中制作一个 VLA 时,它main是一个“全局 VLA”之类的对象,它会持续到程序终止?

4

4 回答 4

3

您可以在 main 中使用 alloca/VLA,但为什么呢?

使用它们的典型原因是如果您有一些性能敏感的部分被大量调用,并且您不希望 malloc/free 的开销。对于 main,您的数据在程序开始时分配一次,因此几次 malloc 调用的开销可以忽略不计。

另一个不在 main 中使用 alloca/VLA 的原因是它们消耗堆栈空间,与堆空间相比,这是非常有限的资源。

于 2021-06-28T07:52:25.070 回答
2

取决于你需要多少内存。如果它足够小(比如几百字节左右),您可以安全地alloca使用main()或使用 VLA。

但是,如果这些数组的大小有一个不是很大的已知上限,那么以该上限作为大小在全局范围内声明它们会更好、更安全。这样您就不会消耗堆栈空间,也不必malloc确保分配成功。然后,任何正在阅读的人也很清楚,这段记忆的存在时间与程序一样长。

如果尺寸可以任意大,那么最好的办法就是malloc()像你现在一样继续使用。顺便说一句,即使您在程序的整个生命周期内调用malloc()main()使用它,在退出之前释放它仍然被认为是一种好习惯。

于 2021-06-28T07:57:05.240 回答
1

从技术上讲不是,因为在函数中声明的任何变量都不是全局的。但是你可以这样做:

char *buffer;

int main(void) {
    char buf[size];
    buffer = buf;

这将为您提供一个全局访问缓冲区的接口。

在这一点上,有什么理由不使用 alloca 而不是 malloc

这是一个通常应该反过来问的问题。有什么理由使用alloca代替malloc吗?如果您有性能问题,请考虑更改,但如果您只想避免使用free,我会说这是一个不好的理由。

但我真的不明白这里的重点。如果您有一个分配的缓冲区,您希望从程序开始到结束时一直存在,那么只需在 main 函数的末尾释放它即可。

int main(void) {
    char *buf = malloc(size);
    // Do work
    free(buf);
}

我写了一个关于和 VLA:s 的长答案alloca,你可能会觉得有用。我真的需要malloc吗?

于 2021-06-28T08:26:24.713 回答
1

VLA(由标准定义)和非标准alloca都旨在用于在本地范围内分配临时的小型数组。没有其他的。

在堆栈上分配大对象是一个众所周知的微妙和严重堆栈溢出错误的来源。这就是您应该避免使用大型 VLA 和alloca对象的原因。每当您需要文件范围内的大对象时,它们应该是static数组或动态分配的malloc.

应该注意的是,堆栈分配通常比堆分配快,因为堆栈分配不需要自己关心查找、碎片和其他特定于堆实现的问题。堆栈分配只是说“这 100 个字节是我的”,然后你就可以开始了。

关于“堆栈与堆”的一般混淆,请参阅在堆栈和堆上分配了什么?

你甚至不能在文件范围内放置一个标准的 VLA,因为数组大小需要是一个整数常量表达式。加上标准(C17 6.7.6)明确规定您不得:

如果标识符被声明为具有静态或线程存储持续时间的对象,则它不应具有可变长度数组类型。

至于alloca它不是标准的 C 语言,因此很糟糕。但它也很糟糕,因为它没有任何类型安全性,因此首选 VLA alloca- 它更安全,更便携。

需要注意的是,现代编程中 VLA 的主要目的是启用指向 VLA 的指针,而不是分配 VLA 类型的数组对象,这是一个使用受限的特性。


我什至从未释放它们,因为当应用程序终止时操作系统已经自动回收分配的内存。

虽然这是正确的,但手动调用 free() 仍然被认为是一种好习惯。因为如果你在程序的某个地方有任何堆损坏或与指针相关的错误,你会在调用 free() 时崩溃。这是一件好事,因为它允许您在开发过程中及早发现此类(常见)错误。

(如果您担心 free() 的性能,您可以从发布版本中排除 free() 调用,并仅在调试版本中使用它们。虽然关闭程序时性能很少成为问题 - 通常您可以关闭如果有的话,关闭 GUI,然后让程序在后台处理清理代码。)

于 2021-06-28T08:26:37.187 回答