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

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

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

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


当前回答

虽然大多数答案都集中在真正的内存泄漏(这是不正确的,因为它们是草率编码的标志),但这个问题的这一部分对我来说似乎更有趣:

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

如果使用了相关的内存,则在程序结束之前不能释放它。释放是由程序退出还是由操作系统完成并不重要。只要有文档记录,这样更改就不会引入真正的内存泄漏,并且在图中不涉及c++析构函数或C清理函数。未关闭的文件可能通过泄漏的file对象显示,但缺少fclose()也可能导致缓冲区不被刷新。

所以,回到最初的情况,在我看来,它本身是完全OK的,以至于Valgrind,最强大的泄漏探测器之一,只会在要求时处理此类泄漏。在Valgrind上,当您覆盖一个指针而没有事先释放它时,它会被认为是内存泄漏,因为它更有可能再次发生,并导致堆无休止地增长。

然后,就没有仍然可以访问的nfreed内存块了。我们可以确保在出口释放所有人,但这本身就是浪费时间。关键是他们之前能不能被释放。降低内存消耗在任何情况下都是有用的。

其他回答

No.

作为专业人士,我们不应该问自己“这样做是否合适?”,而应该问自己“这样做是否有一个好的理由?”“寻找内存泄漏是一种痛苦”并不是一个好的理由。

我喜欢把事情简单化。简单的规则是,我的程序应该没有内存泄漏。

这也让我的生活变得简单。如果我检测到内存泄漏,我会消除它,而不是通过一些复杂的决策树结构来确定它是否是“可接受的”内存泄漏。

它类似于编译器警告——警告对我的特定应用程序是致命的吗?也许不是。

但归根结底,这是一个职业纪律问题。容忍编译器警告和容忍内存泄漏是一个坏习惯,最终会给我带来麻烦。

举个极端的例子,外科医生把手术设备留在病人体内是可以接受的吗?

尽管移除设备的成本/风险可能会超过保留设备的成本/风险,并且可能在某些情况下它是无害的,但如果我在外科医生网站上看到这个问题,看到除了“不”之外的任何答案,这将严重削弱我对医疗行业的信心。

如果是第三方图书馆把这种情况强加给我,我会严重怀疑该图书馆的整体质量。这就像我试驾一辆车,发现其中一个杯托里有几个松动的垫圈和螺母——这本身可能不是什么大问题,但这表明我缺乏对质量的承诺,所以我会考虑其他选择。

不,你不应该有漏洞,操作系统会为你清理。原因(据我所知,在上面的答案中没有提到)是你永远不知道什么时候你的main()会在另一个程序中作为函数/模块被重用。如果你的main()在其他人的软件中经常被调用,那么这个软件就会有内存泄漏,随着时间的推移会消耗内存。

KIV

考虑这样一种情况,该应用程序后来从另一个应用程序中使用,可以在单独的窗口中打开其中的几个应用程序,也可以依次打开其中的几个应用程序来执行某些操作。如果它不是作为一个进程运行,而是作为一个库运行,那么调用程序会泄漏内存,因为您以为您冷跳过了内存清理。

使用一些智能指针,自动为你做(例如scoped_ptr从Boost库)

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

这不是真的。操作系统通常以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服务器需要处理一个又一个的请求——保持一些“松弛”的可用内存是有意义的,这样你就不需要一直向操作系统请求内存了。

我完全同意JohnMcG的观点,只是想补充一点,我自己也有问题,无法及时发现真实的、潜在的严重内存泄漏,只是因为人们已经接受了良性的内存泄漏。随着时间的推移,这些病毒变得如此之多,在大量的良性病毒中发现严重病毒就变得越来越困难。

因此,至少为了你的程序员同事(也是为了你自己的未来),请尽快消除它们。