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


当前回答

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

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

其他回答

你说得对,不会造成伤害,直接退出会更快

原因有很多:

All desktop and server environments simply release the entire memory space on exit(). They are unaware of program-internal data structures such as heaps. Almost all free() implementations do not ever return memory to the operating system anyway. More importantly, it's a waste of time when done right before exit(). At exit, memory pages and swap space are simply released. By contrast, a series of free() calls will burn CPU time and can result in disk paging operations, cache misses, and cache evictions.

关于未来代码重用的可能性,为毫无意义的操作的确定性辩护:这是一个考虑,但可以说这不是敏捷的方式。YAGNI !

几乎每个现代操作系统都会在程序退出后恢复所有已分配的内存空间。我能想到的唯一例外可能是像Palm OS这样的东西,其中程序的静态存储和运行时内存几乎是一样的,所以不释放可能会导致程序占用更多的存储空间。(我只是在猜测。)

所以一般来说,这样做没有什么坏处,除了存储容量超过所需的运行时成本。当然,在您给出的示例中,您希望保留可能被使用的变量的内存,直到它被清除。

然而,一旦你不再需要内存,就立即释放内存,并在程序退出时释放你仍然拥有的内存,这被认为是一种很好的方式。它更像是一种了解您正在使用哪些内存的练习,并考虑是否仍然需要它。如果不进行跟踪,可能会出现内存泄漏。

On the other hand, the similar admonition to close your files on exit has a much more concrete result - if you don't, the data you wrote to them might not get flushed, or if they're a temp file, they might not get deleted when you're done. Also, database handles should have their transactions committed and then closed when you're done with them. Similarly, if you're using an object oriented language like C++ or Objective C, not freeing an object when you're done with it will mean the destructor will never get called, and any resources the class is responsible might not get cleaned up.

在OSTEP操作系统本科课程的在线教科书中,有一个章节恰好讨论了你的问题。

相关的章节是在第6页的内存API章节中“忘记释放内存”,给出了如下解释:

在某些情况下,不调用free()似乎是合理的。为 例如,你的程序是短命的,很快就会退出;在这种情况下, 当进程死亡时,操作系统将清理它分配的所有页面 因此,内存泄漏本身不会发生。虽然这当然“有效” (见第7页的旁白),这可能是一个坏习惯,所以要警惕 选择这样的策略

这段摘录是在介绍虚拟内存概念的上下文中。基本上,在本书的这一点上,作者解释了操作系统的目标之一是“虚拟化内存”,也就是说,让每个程序都相信它可以访问一个非常大的内存地址空间。

在幕后,操作系统会将用户看到的“虚拟地址”转换为指向物理内存的实际地址。

但是,共享物理内存等资源需要操作系统跟踪哪些进程正在使用它。因此,如果一个进程终止,那么在操作系统的能力和设计目标范围内回收该进程的内存,以便它可以重新分配并与其他进程共享内存。


编辑:节选中提到的旁白复制如下。

ASIDE: WHY NO MEMORY IS LEAKED ONCE YOUR PROCESS EXITS When you write a short-lived program, you might allocate some space using malloc(). The program runs and is about to complete: is there need to call free() a bunch of times just before exiting? While it seems wrong not to, no memory will be "lost" in any real sense. The reason is simple: there are really two levels of memory management in the system. The first level of memory management is performed by the OS, which hands out memory to processes when they run, and takes it back when processes exit (or otherwise die). The second level of management is within each process, for example within the heap when you call malloc() and free(). Even if you fail to call free() (and thus leak memory in the heap), the operating system will reclaim all the memory of the process (including those pages for code, stack, and, as relevant here, heap) when the program is finished running. No matter what the state of your heap in your address space, the OS takes back all of those pages when the process dies, thus ensuring that no memory is lost despite the fact that you didn’t free it. Thus, for short-lived programs, leaking memory often does not cause any operational problems (though it may be considered poor form). When you write a long-running server (such as a web server or database management system, which never exit), leaked memory is a much bigger issue, and will eventually lead to a crash when the application runs out of memory. And of course, leaking memory is an even larger issue inside one particular program: the operating system itself. Showing us once again: those who write the kernel code have the toughest job of all... from Page 7 of Memory API chapter of Operating Systems: Three Easy Pieces Remzi H. Arpaci-Dusseau and Andrea C. Arpaci-Dusseau Arpaci-Dusseau Books March, 2015 (Version 0.90)

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

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

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

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

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

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

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

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

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