在C或c++应用程序中出现内存泄漏是可以接受的吗?

如果分配一些内存并一直使用到应用程序中的最后一行代码(例如,全局对象的析构函数),会怎样?只要内存消耗不随时间增长,那么当应用程序终止时(在Windows、Mac和Linux上),是否可以信任操作系统为您释放内存?如果内存一直被使用,直到被操作系统释放,您会认为这是真正的内存泄漏吗?

如果是第三方库将这种情况强加给您,该怎么办?会拒绝使用第三方库,不管它有多好?

我只看到了一个实际的缺点,那就是这些良性泄漏将在内存泄漏检测工具中显示为误报。


当前回答

许多人似乎都有这样的印象:一旦释放内存,它就会立即返回到操作系统,可以被其他程序使用。

这不是真的。操作系统通常以4KiB页面管理内存。malloc和其他类型的内存管理从操作系统获取页面,并在它们认为合适的时候对它们进行子管理。free()很可能不会将页面返回给操作系统,前提是您的程序稍后会误用更多内存。

我并不是说free()从不将内存返回给操作系统。这是有可能发生的,特别是当您正在释放大量内存时。但这并不能保证。

重要的事实是:如果不释放不再需要的内存,那么进一步的malloc必然会消耗更多的内存。但是如果先释放,malloc可能会重新使用释放的内存。

这在实践中意味着什么?这意味着如果你知道你的程序从现在开始不再需要更多的内存(例如它在清理阶段),释放内存就不是那么重要了。但是,如果程序稍后可能分配更多内存,则应该避免内存泄漏——特别是那些可能重复发生的内存泄漏。

关于为什么在终止前释放内存是不好的,请参阅这条评论了解更多细节。

评论者似乎不理解调用free()并不会自动允许其他程序使用释放的内存。但这就是这个答案的全部意义!

因此,为了说服人们,我将演示一个例子,其中free()没有什么好处。为了便于计算,我假设操作系统以4000字节的页面管理内存。

Suppose you allocate ten thousand 100-byte blocks (for simplicity I'll ignore the extra memory that would be required to manage these allocations). This consumes 1MB, or 250 pages. If you then free 9000 of these blocks at random, you're left with just 1000 blocks - but they're scattered all over the place. Statistically, about 5 of the pages will be empty. The other 245 will each have at least one allocated block in them. That amounts to 980KB of memory, that cannot possibly be reclaimed by the operating system - even though you now only have 100KB allocated!

另一方面,您现在可以malloc() 9000多个块,而不会增加程序占用的内存量。

即使free()在技术上可以将内存返回给操作系统,它也可能不会这样做。Free()需要在快速操作和节省内存之间取得平衡。此外,一个已经分配了大量内存然后释放它的程序很可能会再次这样做。web服务器需要处理一个又一个的请求——保持一些“松弛”的可用内存是有意义的,这样你就不需要一直向操作系统请求内存了。

其他回答

我很惊讶看到这么多关于内存泄漏的错误定义。如果没有一个具体的定义,关于它是否是坏事的讨论就不会有任何结果。

正如一些评论员正确地指出的那样,只有当进程分配的内存超出作用域,以至于该进程不再能够引用或删除它时,才会发生内存泄漏。

A process which is grabbing more and more memory is not necessarily leaking. So long as it is able to reference and deallocate that memory, then it remains under the explicit control of the process and has not leaked. The process may well be badly designed, especially in the context of a system where memory is limited, but this is not the same as a leak. Conversely, losing scope of, say, a 32 byte buffer is still a leak, even though the amount of memory leaked is small. If you think this is insignificant, wait until someone wraps an algorithm around your library call and calls it 10,000 times.

我认为没有任何理由允许在您自己的代码中泄漏,无论多么小。现代编程语言,如C和c++,不遗余力地帮助程序员防止此类泄漏,并且很少有好的理由不采用好的编程技术——特别是在与特定的语言功能相结合时——来防止泄漏。

对于现有的或第三方代码,您对质量的控制或进行更改的能力可能非常有限,这取决于泄漏的严重程度,您可能被迫接受或采取缓解措施,例如定期重新启动进程以减少泄漏的影响。

更改或替换现有的(泄漏的)代码可能是不可能的,因此您可能不得不接受它。然而,这并不等同于宣称它是OK的。

只要您的内存利用率不随着时间的推移而增加,这取决于情况。如果你在服务器软件中做很多复杂的同步,比如启动阻塞系统调用的后台线程,那么完全关闭可能太复杂了。在这种情况下,备选方案可能是:

直到进程退出才清理内存的库。 您编写了额外的500行代码,并向类中添加了另一个互斥量和条件变量,以便它可以从测试中干净地关闭—但是这些代码从未在生产中使用,在生产中服务器只会因崩溃而终止。

我相信有人能想出一个理由说“是”,但不会是我。 与其说“不”,我要说的是,这不应该是一个“是”或“否”的问题。 有许多方法可以管理或控制内存泄漏,许多系统都有内存泄漏。

在离开地球的设备上有NASA的系统为这个做了计划。系统会经常自动重启,这样内存泄漏就不会对整体操作造成致命影响。这只是一个遏制的例子。

如果它是故意的,它真的不是一个泄漏,它不是一个问题,除非它是一个相当大的内存,或者可以增长到一个相当大的内存。在程序的生命周期内不清理全局分配是很常见的。如果泄漏是在服务器或长时间运行的应用程序中,随着时间的推移而增长,那么这就是一个问题。

通常,独立应用程序中的内存泄漏不是致命的,因为它会在程序退出时被清除。

对于那些被设计为不退出的服务器程序,您该如何处理?

如果你是那种不设计和实现资源分配和释放正确的代码的程序员,那么我不想与你或你的代码有任何关系。如果您不关心清理泄漏的内存,那么锁呢?你也把他们留在那里吗?你是否在不同的目录中放置了一堆临时文件?

泄露内存并让程序清理?不。绝对不是。这是一个坏习惯,会导致bug、bug、更多的bug。

自己收拾干净。你妈已经不在这里工作了。