我们都被教导必须释放每个已分配的指针。不过,我有点好奇不释放内存的真正代价。在一些明显的情况下,比如在循环内部或线程执行的一部分调用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?


当前回答

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

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

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

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

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

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

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

其他回答

如果您正在从头开始开发一个应用程序,那么您可以在何时调用free方面做出一些明智的选择。您的示例程序很好:它分配内存,也许您让它工作几秒钟,然后关闭,释放它所要求的所有资源。

但是,如果您正在编写其他任何东西——服务器/长时间运行的应用程序,或供其他人使用的库,则应该期望对malloc的所有内容调用free。

暂时忽略实用主义的一面,遵循更严格的方法,并强迫自己释放您malloc的所有内容要安全得多。如果您没有在编写代码时监视内存泄漏的习惯,那么很容易就会出现一些内存泄漏。换句话说,是的,你可以没有它;不过,请小心。

不释放变量并没有真正的危险,但是如果将一个内存块的指针分配给另一个内存块而不释放第一个块,第一个块将不再可访问,但仍然占用空间。这就是所谓的内存泄漏,如果您经常这样做,那么您的进程将开始消耗越来越多的内存,从其他进程占用系统资源。

如果进程是短期的,那么通常可以这样做,因为当进程完成时,所有分配的内存都会被操作系统回收,但我建议养成释放所有不再使用的内存的习惯。

为这个进程分配的所有内存将被OS标记为未使用,然后重用,因为内存分配是由用户空间函数完成的。

想象OS是一个上帝,而记忆是创造一个过程世界的材料,上帝用一些材料创造了一个世界(或者说OS保留了一些内存并在其中创造了一个过程)。无论这个世界上的生物做了什么,不属于这个世界的物质都不会受到影响。在这个世界过期后,OS神,可以回收分配给这个世界的材料。

现代操作系统在释放用户空间内存方面可能有不同的细节,但这必须是操作系统的基本职责。

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

来源:分配和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!

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

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

真正的结果是什么?

你的程序泄露了内存。根据您的操作系统,它可能已经恢复。

大多数现代桌面操作系统确实会在进程终止时恢复泄漏的内存,这使得忽略这个问题变得很常见(从这里可以看到许多其他答案)。

但是您依赖的是一个不属于该语言的安全特性,您不应该依赖它。您的代码可能运行在这样一个系统上,该行为下次会导致“硬”内存泄漏。

你的代码最终可能会在内核模式下运行,或者在老式/嵌入式操作系统上运行,这些操作系统不采用内存保护作为权衡。(mmu占用芯片空间,内存保护成本额外的CPU周期,并且要求程序员自己清理并不过分)。

您可以以任何您喜欢的方式使用和重用内存(和其他资源),但请确保在退出之前释放了所有资源。