我们都被教导必须释放每个已分配的指针。不过,我有点好奇不释放内存的真正代价。在一些明显的情况下,比如在循环内部或线程执行的一部分调用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被标记) 这只会产生错误的和不可移植的代码。

其他回答

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

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

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

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

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

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

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

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

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

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

几乎每个现代操作系统都会在程序退出后恢复所有已分配的内存空间。我能想到的唯一例外可能是像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.

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

原因有很多:

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 !