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

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

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

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


当前回答

我相信答案是否定的,永远不要允许内存泄漏,我有一些我没有看到明确说明的原因。这里有很好的技术答案,但我认为真正的答案取决于更多的社会/人类原因。

(首先,请注意,正如其他人所提到的,真正的泄漏是当您的程序在任何时候失去对已分配内存资源的跟踪时。在C语言中,当你malloc()指向一个指针并让该指针离开作用域而没有先执行free()时,就会发生这种情况。

你做决定的关键在于习惯。当你用一种使用指针的语言编写代码时,你会经常使用指针。指针是危险的;它们是向代码中添加各种严重问题的最简单方法。

当你在编程的时候,有时你会很专注,有时你会很累、生气或担心。在那些有点分心的时间里,你会更多地自动编码。自动驾驶效果不会区分一次性代码和大型项目中的模块。在此期间,您所建立的习惯将最终出现在您的代码库中。

所以,不,永远不要允许内存泄漏,就像你在换车道时仍然应该检查盲点一样,即使你是路上唯一的车。当你活跃的大脑分心时,好习惯可以让你避免灾难性的失误。

除了“习惯”问题之外,指针是复杂的,通常需要大量的脑力来在精神上跟踪。当涉及到指针的使用时,最好不要“搅浑水”,特别是当您是编程新手时。

还有更多的社交方面。通过正确使用malloc()和free(),任何查看您的代码的人都会感到轻松;你在管理你的资源。然而,如果你不这样做,他们马上就会怀疑有问题。

也许您已经发现内存泄漏在这种情况下不会造成任何损害,但是代码的每个维护者在阅读这段代码时也必须在自己的头脑中解决这个问题。通过使用free(),您甚至不需要考虑这个问题。

最后,编程是用一种明确的语言编写一个过程的心理模型,这样人和计算机就可以完全理解所述过程。好的编程实践的一个重要部分是永远不要引入不必要的歧义。

智能编程是灵活和通用的。糟糕的编程是模棱两可的。

其他回答

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

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

我想你已经回答了自己的问题。最大的缺点是它们如何干扰内存泄漏检测工具,但我认为这个缺点对于某些类型的应用程序来说是一个巨大的缺点。

我使用的遗留服务器应用程序应该是坚如磐石的,但它们有泄漏,并且全局变量确实妨碍了内存检测工具。这是件大事。

在杰瑞德·戴蒙德(Jared Diamond)的《崩塌》(Collapse)一书中,作者想知道那个人在想什么,他砍倒了复活节岛上的最后一棵树,而这棵树是他建造独木舟离开该岛所需要的。我想知道许多年前第一个全局变量被添加到我们的代码库的那一天。那是它应该被抓住的日子。

是的,内存泄漏可能是两害相权取其轻。虽然正确性很重要,但在执行完全内存释放时,性能或系统的稳定性可能会受到影响,并且释放内存和销毁对象所花费的风险和时间可能比仅仅退出进程更可取。

一般来说,在周围留下内存通常是不可接受的。理解代码运行的所有作用域是很困难的,在某些情况下,这可能导致泄漏成为灾难性的。

如果分配一些内存并一直使用到应用程序中的最后一行代码(例如,全局对象的析构函数),会怎样?

在这种情况下,您的代码可能会移植到更大的项目中。这可能意味着您的对象的生命周期太长(它持续整个程序,而不仅仅是需要它的实例),或者如果创建并销毁全局变量,它就会泄漏。

当应用程序终止时,是否可以信任操作系统为您释放内存

当一个短生命周期的程序创建大型c++集合(例如std::map)时,每个对象至少有2个分配。对CPU来说,遍历这个集合以销毁对象需要花费实时时间,而让对象泄漏并由操作系统清理具有性能优势。计数器,有一些资源没有被操作系统整理(例如共享内存),并且不破坏代码中的所有对象会打开一些持有这些未释放资源的风险。

如果是第三方库将这种情况强加给您,该怎么办?

首先,我会为释放资源的close函数提出一个bug。是否可以接受的问题,是基于库提供的优势(成本、性能、可靠性)是否比使用其他库或自己编写更好。

一般来说,除非库可以重新初始化,否则我可能不会关心。

报告泄漏内存的可接受时间。

关闭期间的服务。这里需要在时间性能和正确性之间进行权衡。 一个破碎的无法被摧毁的物体。我已经能够检测到一个失败的对象(例如,由于异常被捕获),当我尝试并销毁对象时,结果是挂起(持有锁)。 内存检查错误报告。

关闭期间的服务

如果操作系统即将关闭,所有资源将被清理。不执行正常进程关闭的优点是,用户在关闭时可以获得更快的性能。

破损的物品

在我的过去,我们发现了一个对象(并为该团队提出了一个缺陷),如果它们在某些点崩溃,它们就会被破坏,该对象中的所有后续函数都会导致挂起。

尽管忽略内存泄漏是一种糟糕的做法,但关闭进程、泄漏对象及其内存比导致挂起更有效。

泄漏检查错误报告

一些泄漏检查器通过检测对象来工作,并以与全局变量相同的方式工作。它们有时会忽略另一个全局对象有一个有效的析构函数,在它们完成后调用,这将释放内存。

不,它们不是可以的,但是我已经实现了一些分配器、内存转储器和泄漏检测器,并且发现从实用的角度来看,允许人们将这样的分配标记为“就泄漏报告而言,不是泄漏”是很方便的……

这有助于使泄漏报告更有用……不要充斥着“静态范围内的动态分配不被程序退出释放”

当应用程序关闭时,可以认为最好不要释放内存。

理论上,操作系统应该释放应用程序使用的资源,但总有一些资源是这个规则的例外。所以要小心。

退出应用程序的好处是:

操作系统只释放一个块,而不是很多很多小块。这意味着关机速度要快得多。尤其是在内存管理缓慢的Windows上。

只是退出的坏处其实有两点

很容易忘记释放操作系统没有跟踪的资源,或者操作系统可能会等待一段时间才释放。一个例子是TCP套接字。 内存跟踪软件将报告在退出时未释放的所有内容为泄漏。

因此,您可能希望有两种关机模式,一种是针对最终用户的快速且不友好的关机模式,另一种是针对开发人员的缓慢且彻底的关机模式。只是要确保两者都测试:)