内存泄漏是否正常?

在C或c++应用程序中使用内存泄漏是否可以接受?

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

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

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

37748 次浏览

在理论上没有,在实践中这取决于

这实际上取决于程序处理了多少数据,程序运行的频率以及它是否持续运行。

如果我有一个快速程序,读取少量数据进行计算并退出,那么就永远不会注意到一个小的内存泄漏。因为程序不会运行很长时间,并且只使用少量的内存,所以当程序存在时,泄漏将很小并被释放。

另一方面,如果我有一个处理数百万条记录并运行很长时间的程序,一个小的内存泄漏可能会在足够的时间内使机器停机。

对于有泄漏的第三方库,如果它们导致问题,要么修复库,要么找到更好的替代方案。如果不造成问题,这真的重要吗?

除非“使用”的内存量不断增长,否则我不认为这是内存泄漏。有一些未释放的内存,虽然不是理想的,但不是一个大问题,除非所需的内存数量不断增长。

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

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

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

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

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

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

在应用程序运行后清理操作系统在概念上没有问题。

这实际上取决于应用程序以及它将如何运行。在需要运行数周的应用程序中不断发生的泄漏必须得到处理,但是一个不需要太多内存就能计算结果的小工具应该不是问题。

许多脚本语言不垃圾收集循环引用是有原因的……对于它们的使用模式,这不是一个实际的问题,因此浪费的资源和浪费的内存一样多。

我看到了和所有场景问题一样的问题,比如:当程序改变时,会发生什么?突然,这个小内存泄漏被调用了1000万次,而程序的结尾在不同的地方,所以它很重要?如果它在库中,那么请向库维护者记录错误,不要在您自己的代码中泄漏。

我的回答是没有。

从理论上讲,如果你把东西弄得乱七八糟,操作系统会帮你清理干净(这很粗鲁,但由于计算机没有感情,这可能是可以接受的)。但是,您无法预测程序运行时可能发生的每一种情况。因此(除非您能够对某些行为进行正式的证明),从专业的角度来看,造成内存泄漏是不负责任和草率的。

如果第三方组件泄漏内存,这是一个非常强烈的反对使用它的理由,不仅因为即将发生的影响,而且因为它表明程序员工作草率,这也可能影响其他指标。现在,当考虑遗留系统时,这是困难的(考虑web浏览组件:据我所知,它们所有泄漏内存),但这应该是标准。

这是一个非常特定的领域,几乎不值得回答。动动你的脑袋。

  • 航天飞机操作系统:不,不允许内存泄漏
  • 快速开发概念验证代码:修复所有这些内存泄漏是浪费时间。

还有一系列的中间情况。

延迟产品发布以修复除最严重内存泄漏外的所有内存泄漏的机会成本($$$)通常会让“草率或不专业”的感觉相形见绌。你的老板付钱给你是为了给他赚钱,而不是为了得到温暖、模糊的感觉。

如果分配内存并一直使用到程序的最后一行,这就不是泄漏。如果您分配内存并忘记它,即使内存数量没有增长,这也是一个问题。已分配但未使用的内存可能导致其他程序运行速度变慢或根本不运行。

您必须首先认识到,感知到的内存泄漏和实际的内存泄漏之间有很大的区别。分析工具经常会报告许多无关紧要的东西,并将一些实际上没有泄漏的东西(内存或资源,如句柄等)标记为泄漏。通常情况下,这是由于分析工具的架构。例如,某些分析工具将运行时对象报告为内存泄漏,因为它从未看到这些对象被释放。但是重新分配发生在运行时的关闭代码中,分析工具可能无法看到。

尽管如此,仍然会有一些时候,您会遇到实际的内存泄漏,这些泄漏要么很难发现,要么很难修复。现在的问题是,是否可以将它们保留在代码中?

理想的答案是:“不,从来没有。”一个更务实的答案可能是“不,几乎从来没有。”在现实生活中,你常常只有有限的资源和时间来解决问题,而你的任务却无穷无尽。当其中一项任务是消除内存泄漏时,收益递减法则经常会发挥作用。您可以在一周内消除应用程序中98%的内存泄漏,但剩下的2%可能需要几个月的时间。在某些情况下,如果不进行重大的代码重构,甚至不可能消除应用程序架构造成的某些泄漏。你必须权衡去除剩余2%的成本和收益。

我想以你的情况,答案可能是没关系。但是您肯定需要记录内存泄漏是一个有意识的决定。你不希望一个维护程序员出现,把你的代码放到一个函数中,然后调用它一百万次。因此,如果您决定泄漏是可以接受的,那么您需要为将来可能不得不在该程序上工作的任何人记录它(用大写字母)。

如果这是一个第三方库,你可能会被困住。但是一定要记录泄漏的发生。

但基本上,如果内存泄漏是一个已知的数量,比如512 KB的缓冲区,那么它就不是问题。如果内存泄漏持续增长,比如每次调用库调用时,内存都会增加512KB,但没有释放,那么可能有问题。如果您记录它并控制调用执行的次数,那么它可能是可管理的。但是你真的需要文档,因为虽然512不是很多,但是512超过一百万次调用就很多了。

此外,您还需要检查您的操作系统文档。如果这是一个嵌入式设备,那么操作系统可能不会从退出的程序中释放所有内存。我不确定,也许这不是真的。但这是值得研究的。

我同意vfilby -这要看情况。在Windows中,我们将内存泄漏视为相对严重的错误。但是,这很大程度上取决于分量。

例如,对于很少运行且运行时间有限的组件,内存泄漏不是很严重。这些组件运行,完成工作,然后退出。当它们退出时,所有内存都被隐式释放。

但是,服务或其他长期运行组件(如shell)中的内存泄漏非常严重。原因是这些bug会随着时间的推移“窃取”内存。恢复的唯一方法是重新启动组件。大多数人不知道如何重新启动服务或shell——所以如果他们的系统性能受到影响,他们就重新启动。

所以,如果你有一个泄漏-评估它的影响两种方式

  1. 你的软件和你的用户体验。
  2. 对于系统(和用户)来说,节省系统资源是非常重要的。
  3. 修复对维护和可靠性的影响。
  4. 在其他地方造成倒退的可能性。

前甲板

从历史上看,在某些边缘情况下,它在某些操作系统上确实很重要。这些边缘情况在未来可能会存在。

这里有一个例子,在Sun 3时代的SunOS上,如果一个进程使用了exec(或者更传统的fork,然后是exec),那么后续的新进程将继承与父进程相同的内存占用,并且它不能被收缩。如果父进程分配了1/ 2g内存,并且在调用exec之前没有释放它,那么子进程将开始使用同样的1/ 2g内存(即使它没有分配)。这种行为由SunTools(他们的默认窗口系统)最好地展示出来,这是一个占用内存的系统。它生成的每个应用程序都是通过fork/exec创建的,并继承了SunTools的占用空间,很快就填满了交换空间。

不。

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

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

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

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

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

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

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

- - - - - -

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

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

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

在这类问题中,语境就是一切。就我个人而言,我不能忍受漏洞,在我的代码中,如果它们突然出现,我就会竭尽全力去修复它们,但修复漏洞并不总是值得的,当人们按小时支付我的报酬时,我有时会告诉他们,我的费用不值得我修复他们代码中的漏洞。让我给你们举个例子:

我对一个项目进行了分类,做了一些改进工作,修复了很多bug。在应用程序初始化期间有一个漏洞,我追踪到,并完全理解。正确地修复它可能需要一天左右的时间来重构一段其他功能代码。我本可以做一些hack的事情(比如将值填充到一个全局变量中,然后在我知道它不再被使用的时候抓取它),但这只会给下一个不得不接触代码的人带来更多的困惑。

就我个人而言,我一开始就不会以这种方式编写代码,但我们大多数人并不总是在设计良好的原始代码库上工作,有时你必须务实地看待这些事情。修复150字节泄漏所花费的时间可以用来改进算法,从而减少兆字节的内存。

最终,我决定为一个使用大约1g内存并运行在专用机器上的应用程序泄露150个字节不值得修复,所以我写了一条评论说它被泄露了,为了修复它需要改变什么,以及为什么当时不值得。

即使您确定“已知的”内存泄漏不会造成严重破坏,也不要这样做。在最好的情况下,它会为你在不同的时间和地点犯下类似的、可能更严重的错误铺平道路。

对我来说,问这个问题就像问“我可以在凌晨3点没有人的时候闯红灯吗?”当然,在那个时候它可能不会造成任何麻烦,但它将为你在高峰时间做同样的事情提供一个杠杆!

随着时间的推移,我看到的“良性”泄漏的数量一只手就能数得过来。

所以我的答案是肯定的。

一个例子。如果你有一个单例资源,需要一个缓冲区来存储一个循环队列或deque,但不知道缓冲区需要多大,也负担不起锁定或每个读取器的开销,那么分配一个指数倍的缓冲区,但不释放旧的缓冲区,将会泄漏每个队列/deque的有限内存量。这样做的好处是,它们大大加快了每次访问的速度,并且可以通过不冒争夺锁的风险来改变多处理器解决方案的渐近性。

我已经看到这种方法在非常明确的固定计数的事情上有很大的好处,比如每cpu的工作窃取deques,而在Hans Boehm的C/ c++保守垃圾收集器中用于保存单例/proc/self/maps状态的缓冲区中,这种方法用于检测根集等。

虽然从技术上讲这是一个泄漏,但这两种情况在大小上都是有限制的,并且在可增长的循环工作窃取deque情况下,有巨大的性能优势,以换取队列内存使用的有界因子增加2。

如果你在程序开始时分配了一堆内存,但退出时没有释放它,这本身并不是内存泄漏。内存泄漏是指当程序循环遍历一段代码时,该代码分配堆,然后在没有释放它的情况下“失去跟踪”。

事实上,在退出之前不需要调用free()或delete。当进程退出时,它的所有内存都被操作系统回收(POSIX当然就是这种情况。在其他操作系统上-特别是嵌入式的- YMMV)。

对于退出时不释放内存,我唯一要注意的是,如果你重构了你的程序,例如,它变成了一个等待输入的服务,做你的程序所做的任何事情,然后循环等待另一个服务调用,那么你所编写的可以就会变成内存泄漏。

这已经讨论过令人作呕。最重要的是,内存泄漏是一个bug,必须修复。如果第三方库泄露了内存,就会让人怀疑它还有什么问题,不是吗?如果你要造一辆汽车,你会使用一个偶尔漏油的发动机吗?毕竟,引擎是别人做的,所以这不是你的错,你不能修,对吧?

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

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

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

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

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

看来你对“内存泄漏”的定义是“我自己不清理的内存”。所有现代操作系统都会在程序退出时释放它。然而,由于这是一个c++问题,您可以简单地将所讨论的内存包装在适当的std::auto_ptr中,该std::auto_ptr将在超出作用域时调用delete。

首先,让我们把定义更正一下。内存泄漏是指动态分配内存时,例如使用malloc(),如果没有相应的free,所有对内存的引用都将丢失。制作一个简单的方法是这样的:

#define BLK ((size_t)1024)
while(1){
void * vp = malloc(BLK);
}

注意,每次在while(1)循环中,分配1024(+开销)字节,并将新地址分配给vp;没有指向之前malloc 'Ed块的剩余指针。这个程序保证运行到堆用完为止,并且没有办法恢复任何malloc'ed内存。内存从堆中“泄漏”出来,再也看不见了。

你所描述的,听起来就像

int main(){
void * vp = malloc(LOTS);
// Go do something useful
return 0;
}

你分配内存,使用它直到程序结束。这是内存泄漏;它不会损害程序,并且当程序终止时,所有的内存将被自动清除。

一般来说,应该避免内存泄漏。首先,因为就像你头顶上的高度和飞机库里的燃料一样,已经泄漏且无法恢复的内存是无用的;其次,在一开始就正确编码,不泄漏内存,比后来发现内存泄漏要容易得多。

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

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

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

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

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

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

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

通过使用free(),你甚至不需要考虑这个问题。

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

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

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

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

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

重要的事实:如果你不释放你不再需要的内存,进一步的malloc将保证消耗内存。但是如果先释放,malloc可能会重新使用释放的内存。

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

也可以参见这样的评论了解更多关于为什么在终止前释放内存是不好的。

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

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

假设您分配了10,000个100字节的块(为了简单起见,我将忽略管理这些分配所需的额外内存)。这将消耗1MB,或250页。如果你随机释放9000个这样的区块,你就只剩下1000个区块——但它们分散在各个地方。据统计,大约有5页是空的。其他245个至少有一个已分配的块。这相当于980KB的内存,操作系统不可能回收这些内存——即使现在只分配了100KB内存!

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

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

一般情况下,如果遇到无法避免的内存泄漏,则需要更加认真地考虑对象所有权问题。

但对于你的问题,我的答案是在产品代码中,是的。在开发过程中,。这听起来可能有些倒退,但我的理由是:

在你描述的情况下,内存一直保存到程序结束,不释放它是完全可以的。一旦进程退出,操作系统无论如何都会清理。事实上,这可能会让用户体验更好:在我参与的一款游戏中,程序员认为在退出前释放所有内存会更干净,导致程序关闭需要半分钟!只需调用exit()进行快速更改,即可使进程立即消失,并将用户放回到他想要的桌面。

但是,您对调试工具的看法是正确的:它们会突然发作,而且所有的假阳性可能会使查找真正的内存泄漏变得很痛苦。正因为如此,总是编写释放内存的调试代码,并在发布时禁用它。

这实际上取决于创建内存泄漏的对象的使用情况。 如果在使用该对象的应用程序的生命周期内多次创建该对象,那么使用这种方式是不好的。因为会有很多内存泄漏。 另一方面,如果我们有一个对象的实例,而不消耗内存,并且只是少量的泄漏,那么这不是一个问题

当应用程序运行时内存泄漏增加时,内存泄漏就是一个问题。

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

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

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

KIV

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

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

退出应用程序的好处是:

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

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

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

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

只有一种情况:由于不可恢复的错误,程序将自行终止。

最佳实践是始终释放所分配的空间,特别是在编写旨在在整个系统正常运行期间运行的内容时,即使在退出之前进行清理。

这是一个非常简单的规则。以无泄漏为目标进行编程,可以很容易地发现新的泄漏。你会卖给别人一辆你自己造的车吗?你知道它一熄火就会喷到地上?:)

清理函数中的一些if () free()调用是廉价的,为什么不使用它们呢?

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

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

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

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

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

如果你使用它直到main()的尾部,它根本不是一个泄漏(当然,假设有一个受保护的内存系统!)。

事实上,在进程关闭时释放对象绝对是你可以做的最糟糕的事情…操作系统必须返回你创建的每一个页面。关闭文件句柄,数据库连接,当然,但释放内存是愚蠢的。

如果您的代码有任何内存泄漏,即使是已知的“可接受的”泄漏,那么使用任何内存泄漏工具来查找“真正的”泄漏将会非常麻烦。就像留下“可接受的”编译器警告会使查找新的“真正的”警告更加困难一样。

不,它们不是可以的,但我已经实现了一些分配器、内存转储器和泄漏检测器,并发现作为一个实用的问题,允许将这样的分配标记为“就泄密报告而言,这算不上泄密”

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

也许是在细枝末节:如果您的应用程序运行在UNIX上,可能会变成僵尸怎么办?在这种情况下,内存不会被操作系统回收。所以我说你应该在程序退出之前重新分配内存。

在程序的最后一行省略释放内存是完全可以接受的,因为释放它不会对任何事情产生影响,因为程序再也不需要内存了。

我相信,如果你有一个程序,它将运行几秒钟,然后退出,这是可以的,它只是为个人使用。一旦程序结束,任何内存泄漏都会被清除。

当你有一个运行很长时间的程序并且用户依赖它时,问题就来了。另外,让你的程序中存在内存泄漏是一种坏的编码习惯,特别是如果它们可能在某一天将代码转换为其他内容的话。

总之,最好删除内存泄漏。

我在高中上过一门C课,老师说当你malloc的时候一定要确保自由。

但是当我在大学里上另一门课的时候,教授说不给那些只运行一秒钟的小程序免费是可以的。 因此,我认为这不会损害您的程序,但免费提供强大、健康的代码是一种很好的实践。< / p >

我将给出一个不受欢迎但实际的答案,即释放内存总是错误的,除非这样做会减少程序的内存使用。例如,一个程序进行一次或一系列分配来加载它将在整个生命周期中使用的数据集,不需要释放任何东西。在更常见的情况下,一个大型程序有非常动态的内存需求(想想web浏览器),你显然应该尽快释放你不再使用的内存(例如关闭一个选项卡/文档/等等),但是当用户选择单击“退出”时,没有理由释放任何东西,这样做实际上对用户体验有害。

为什么?释放内存需要接触内存。即使您的系统的malloc实现碰巧没有在分配的内存块附近存储元数据,您也可能会遍历递归结构,只是为了找到所有需要释放的指针。

现在,假设您的程序处理了大量的数据,但是在一段时间内没有接触到其中的大部分数据(同样,web浏览器是一个很好的例子)。如果用户正在运行很多应用程序,那么很大一部分数据可能已经被交换到磁盘上了。如果你只是退出(0)或从main返回,它会立即退出。很棒的用户体验。如果你费尽心思想要释放所有的数据,你可能会花5秒钟或更长的时间来交换所有的数据,只是在那之后立即扔掉它。浪费用户的时间。浪费笔记本电脑的电池寿命。浪费硬盘磨损。

这不仅仅是理论上的。每当我发现自己加载了太多的应用程序,磁盘开始抖动时,我甚至不会考虑点击“退出”。我以最快的速度到达一个终端,输入killall -9…因为我知道"退出"只会让情况更糟。

在以前,我可能会说是的,在你的程序中让一些内存泄漏有时是可以接受的(它仍然是快速原型),但现在有了5到6次的经验,即使是跟踪最小的泄漏也会发现一些真正严重的功能错误。在数据实体的生命周期还不清楚的情况下,让程序发生泄漏,显示出严重缺乏分析。总之,了解程序中发生了什么总是一个好主意。

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

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

我想,如果你正在编写一个打算泄漏内存的程序(即测试内存泄漏对系统性能的影响),这是没有问题的。

规则很简单:如果你用完了一些内存就清理它。 有时即使我们稍后需要一些实例,但我们注意到我们占用了大量内存,所以它会影响性能,因为交换到磁盘,我们可以将数据存储到磁盘文件中,然后重新加载它们,有时这种技术会大大优化你的程序

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

如果我理解正确的话,您没有显式地释放内存(可以释放内存,因为您仍然有一个指针),而是依赖于操作系统在进程终止期间释放内存。虽然这对于简单的程序来说似乎没问题,但请考虑这样一种情况:您的代码被移动到一个库中,并成为某个全天候运行的常驻守护进程的一部分。假设这个守护进程每次需要使用您的代码做一些有用的事情时都会生成一个线程,并假设它每小时生成数千个线程。在这种情况下,你会得到真正的内存泄漏。

不幸的是,这种情况在现实生活中并非不可能,一致的内存管理技术可能会使您的生活更轻松。

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

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

占用越来越多内存的进程并不一定是泄漏的。只要它能够引用和释放该内存,那么它就仍然处于进程的显式控制之下,并且没有泄漏。进程很可能设计得很糟糕,特别是在内存有限的系统上下文中,但这与泄漏不同。相反,丢失一个32字节缓冲区的作用域仍然是泄漏,即使泄漏的内存量很小。如果您认为这是无关紧要的,那就等到有人在您的库调用周围包装了一个算法并调用了10,000次。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

关闭期间的服务

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

破损的物品

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

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

泄漏检查错误报告

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

这里有一些很棒的答案。为了给这个问题添加另一个角度,我将解决一个情况,其中内存泄漏不仅是可接受的,而且是可取的:在Windows驱动程序环境中,开发人员提供了一组回调,在需要时由操作系统运行。其中一个回调是'Shutdown'回调,它在系统关闭/重新启动之前运行。与标准情况不同,不仅不需要释放内存(系统很快就会关闭),甚至不鼓励这样做——以使关闭尽可能快,并防止内存管理的开销。