我们都被教导必须释放每个已分配的指针。不过,我有点好奇不释放内存的真正代价。在一些明显的情况下,比如在循环内部或线程执行的一部分调用malloc()时,释放是非常重要的,这样就不会有内存泄漏。但是考虑下面两个例子:

首先,如果我有这样的代码:

int main()
{
    char *a = malloc(1024);
    /* Do some arbitrary stuff with 'a' (no alloc functions) */
    return 0;
}

真正的结果是什么?我的想法是进程死亡,然后堆空间也消失了,所以错过对free的调用没有什么坏处(然而,我确实认识到无论如何拥有它对于闭包、可维护性和良好实践的重要性)。我这样想对吗?

Second, let's say I have a program that acts a bit like a shell. Users can declare variables like aaa = 123 and those are stored in some dynamic data structure for later use. Clearly, it seems obvious that you'd use some solution that will calls some *alloc function (hashmap, linked list, something like that). For this kind of program, it doesn't make sense to ever free after calling malloc because these variables must be present at all times during the program's execution and there's no good way (that I can see) to implement this with statically allocated space. Is it bad design to have a bunch of memory that's allocated but only freed as part of the process ending? If so, what's the alternative?


当前回答

我完全不同意那些说OP是正确的或没有伤害的人。

每个人都在谈论现代和/或传统的操作系统。

但是如果我在一个没有操作系统的环境中呢? 哪里什么都没有?

想象一下,现在您正在使用线程样式的中断并分配内存。 在C标准ISO/IEC:9899中,内存的寿命表示为:

7.20.3 Memory management functions 1 The order and contiguity of storage allocated by successive calls to the calloc, malloc, and realloc functions is unspecified. The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated). The lifetime of an allocated object extends from the allocation until the deallocation.[...]

所以我们不能认为环境在为你做释放的工作。 否则,它将被添加到最后一句:“或直到程序终止。”

换句话说: 不释放内存不仅仅是不好的做法。它生成不可移植且不符合C的代码。 至少可以被视为“正确的”,如果有以下情况:[…]],由environment支持。

但如果你根本就没有操作系统,那就没有人在为你做这项工作了 (我知道通常在嵌入式系统中不会分配和重新分配内存, 但在某些情况下,你可能想这么做。)

在普通的C语言中(OP被标记) 这只会产生错误的和不可移植的代码。

其他回答

===将来的校对和代码重用怎么办?= = =

如果你不编写释放对象的代码,那么你就将代码限制为只有当你可以依赖于进程关闭释放内存时才能安全使用……例如,小型一次性使用项目或“一次性”[1]项目)……你知道这个过程什么时候结束。

如果您确实编写了free()释放所有动态分配内存的代码,那么您就可以在未来验证代码,并让其他人在更大的项目中使用它。


[1]关于“一次性”项目。在“一次性”项目中使用的代码有一种不被丢弃的方法。接下来,十年过去了,你的“一次性”代码仍在使用)。

我听说过一个故事,说有个人写了一些代码,只是为了让他的硬件工作得更好。他说“只是一个爱好,不会有大的和专业的”。多年后,很多人都在使用他的“爱好”代码。

是的,你是对的,你的例子没有造成任何伤害(至少在大多数现代操作系统上没有)。进程退出后,操作系统将恢复进程分配的所有内存。

来源:分配和GC神话(PostScript警告!)

Allocation Myth 4: Non-garbage-collected programs should always deallocate all memory they allocate. The Truth: Omitted deallocations in frequently executed code cause growing leaks. They are rarely acceptable. but Programs that retain most allocated memory until program exit often perform better without any intervening deallocation. Malloc is much easier to implement if there is no free. In most cases, deallocating memory just before program exit is pointless. The OS will reclaim it anyway. Free will touch and page in the dead objects; the OS won't. Consequence: Be careful with "leak detectors" that count allocations. Some "leaks" are good!

也就是说,您应该尽量避免所有内存泄漏!

第二个问题:你的设计还可以。如果你需要存储一些东西直到你的应用程序退出,那么使用动态内存分配是可以的。如果您事先不知道所需的大小,就不能使用静态分配的内存。

这取决于你正在做的项目的范围。在你的问题的背景下,我是说仅仅是你的问题,那就不重要了。

为了进一步解释(可选),我从整个讨论中注意到的一些场景如下:

(1) -如果你在一个嵌入式环境中工作,你不能依靠主操作系统来回收内存,那么你应该释放它们,因为如果不注意的话,内存泄漏真的会使程序崩溃。

(2) -如果你正在做一个个人项目,你不会向任何人透露它,那么你可以跳过它(假设你在主操作系统上使用它),或者出于“最佳实践”的考虑而包含它。

(3) -如果你正在开发一个项目,并计划让它开源,那么你需要对你的受众做更多的研究,并弄清楚释放内存是否是更好的选择。

(4)如果你有一个很大的库,而你的用户只有主操作系统,那么你就不需要释放它,因为他们的操作系统会帮助他们这么做。同时,通过不释放,你的库/程序可能有助于提高整体性能,因为程序不需要关闭每个数据结构,延长关机时间(想象一下,在离开家之前,你要非常缓慢地等待关机……)

我可以继续指定要采取哪一种方法,但这最终取决于您想用程序实现什么。释放内存在某些情况下被认为是很好的实践,但在某些情况下则不是,因此它最终取决于您所处的具体情况,以及在正确的时间提出正确的问题。好运!

退出时不释放内存是完全没问题的;Malloc()从称为“堆”的内存区域分配内存,当进程退出时释放整个堆。

也就是说,人们仍然坚持在退出前释放所有东西的一个原因是,内存调试器(例如Linux上的valgrind)将未释放的块检测为内存泄漏,如果你也有“真正的”内存泄漏,如果你在最后得到“假的”结果,那么发现它们会变得更加困难。

我认为你的两个例子实际上只有一个:free()应该只在进程结束时发生,正如你指出的那样,这是无用的,因为进程正在终止。

但在第二个示例中,唯一的区别是允许未定义的malloc()数量,这可能导致内存耗尽。处理这种情况的唯一方法是检查malloc()的返回代码并采取相应的行动。