关于c ++:内存泄漏是否正常?

Are memory leaks ever ok?

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

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

如果第三方图书馆强迫你这样做呢?不管第三方图书馆有多大,它都会拒绝使用它吗?

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


不。

作为专业人士,我们不应该问自己的问题是,"这样做可以吗?"但更确切地说,"有没有一个很好的理由这样做?""追查记忆泄漏是一种痛苦"并不是一个很好的理由。

我喜欢保持简单。简单的规则是我的程序不应该有内存泄漏。

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

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

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

把事情推向极端,外科医生会不会把一些手术设备留在病人体内?

尽管可能会出现这样的情况,即移动设备的成本/风险超过了离开设备的成本/风险,而且可能会出现无害的情况,如果我在surgeonoverflow.com上看到这个问题并看到除"否"以外的任何答案,这将严重损害我对自己的信心。医学专业。

-

如果第三方图书馆强迫我这样做,我会严重怀疑图书馆的整体质量。就好像我试驾了一辆车,在其中一个杯托上发现了几个松动的垫圈和螺母——这本身可能不是什么大问题,但它表现出对质量缺乏承诺,所以我会考虑其他选择。


我不认为这是内存泄漏,除非正在"使用"的内存量不断增加。拥有一些未释放的内存,虽然不理想,但这不是一个大问题,除非所需的内存量不断增长。


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

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

请注意,每次在while(1)循环中,都会分配1024(+overhead)字节,并将新地址分配给vp;没有剩余的指针指向以前的malloc'ed块。这个程序保证在堆耗尽之前运行,并且没有办法恢复任何malloc'ed内存。内存正在从堆中"泄漏",再也看不到了。

不过,你所描述的听起来像

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

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

通常,您应该避免内存泄漏。首先,因为像你上面的高度和机库里的燃料一样,那些已经泄漏并且无法恢复的记忆是无用的;其次,在开始的时候,正确地编码,而不是泄漏记忆要比以后发现记忆泄漏容易得多。


理论上不,实践上要看情况。

它实际上取决于程序处理的数据量、程序运行的频率以及它是否持续运行。

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

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

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


许多人似乎认为,一旦释放内存,它就会立即返回到操作系统,并可被其他程序使用。

这不是真的。操作系统通常在4kib页面中管理内存。malloc和其他类型的内存管理从操作系统获取页面,并根据需要对其进行子管理。很可能free()不会将页面返回到操作系统,前提是您的程序稍后会内存不足。

我不是说free()永远不会将内存返回到操作系统。这是可能发生的,特别是如果您释放了大量的内存。但没有保证。

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

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

另请参阅此注释,了解有关在终止前释放内存的原因的更多详细信息。

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

所以,为了说服人们,我将演示一个例子,其中free()几乎没有什么好处。为了使数学更容易理解,我将假装操作系统在4000字节的页面中管理内存。

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

另一方面,您现在可以在不增加程序占用的内存量的情况下再添加malloc()9000个块。

即使当free()可以从技术上将内存返回到操作系统时,它也可能不会这样做。free()需要在快速运行和节省内存之间实现平衡。此外,一个已经分配了大量内存,然后又释放了内存的程序很可能会再次这样做。Web服务器需要在一个接一个请求后处理请求—保留一些"可宽延"内存是有意义的,这样您就不需要一直向操作系统请求内存。


在运行应用程序之后,让操作系统清理在概念上没有任何错误。

它实际上取决于应用程序及其运行方式。需要运行数周的应用程序中不断发生的泄漏必须得到处理,但是计算结果而不需要太高内存的小工具不应该是问题。

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


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

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

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

当你在编码的时候,有时你会在舞会上,有时你会感到疲倦、生气或担心。在有些分心的时候,你在自动驾驶仪上编码。自动驾驶效应并不能区分一次性代码和大型项目中的模块。在这些时候,您建立的习惯将最终出现在您的代码库中。

所以不,永远不要让记忆泄漏,因为换车道的时候你仍然应该检查你的盲点,即使你现在是路上唯一的一辆车。在你活跃的大脑分心的时候,良好的习惯可以让你避免灾难性的失误。

除了"习惯"问题之外,指针是复杂的,通常需要大量的脑力来跟踪心理。当涉及到指针的使用时,最好不要"混水",特别是当你刚开始编程时。

还有一个更社会化的方面。通过正确使用malloc()free(),任何查看您的代码的人都会很轻松;您正在管理您的资源。但是,如果你不这样做,他们会立即怀疑有问题。

也许你已经知道了内存泄漏在这种情况下不会伤害任何东西,但是你的代码的每一个维护者在读那段代码的时候,也必须在他的头脑中解决这个问题。通过使用free(),您甚至不需要考虑这个问题。

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

智能编程具有灵活性和通用性。错误的编程不明确。


我认为在你的情况下,答案可能是没关系。但你肯定需要证明内存泄漏是一个有意识的决定。你不想让一个维护程序员来,把你的代码放在一个函数里,然后调用它一百万次。因此,如果您决定泄漏是可以的,您需要记录它(大字母),无论谁可能需要在未来的程序工作。

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

但基本上,如果内存泄漏是一个已知的数量,比如一个512KB的缓冲区或其他什么东西,那么它就不是问题了。如果内存泄漏像每次调用库调用一样不断增长,则内存将增加512KB,并且没有释放,那么您可能会遇到问题。如果您记录它并控制调用的执行次数,那么它可能是可管理的。但是,您真的需要文档,因为尽管512并不多,但超过一百万次的512次呼叫却非常多。

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


我将给出一个不受欢迎但实际可行的答案,即释放内存总是错误的,除非这样做会减少程序的内存使用。例如,一个进行单个分配或一系列分配以加载将在其整个生命周期中使用的数据集的程序不需要释放任何内容。对于具有非常动态的内存需求的大型程序(例如Web浏览器),您应该尽快释放不再使用的内存(例如关闭选项卡/文档等),但当用户选择"退出"时,没有理由释放任何内容,这样做实际上对用户的周期性。

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

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

这不仅仅是理论上的。每当我发现自己加载了太多的应用程序,磁盘开始摇晃时,我甚至不考虑单击"退出"。我尽快到达终点站,然后输入killall-9…因为我知道"退出"只会让事情变得更糟。


我相信有人会有理由说"是",但不会是我。我不是说不,而是说这不应该是一个是/否的问题。有一些方法可以管理或控制内存泄漏,许多系统都有这种方法。

美国国家航空航天局的设备上有一些系统离开了地球,计划这样做。系统会每隔一段时间自动重启一次,这样内存泄漏就不会对整个操作造成致命影响。只是一个遏制的例子。


如果您在程序开始时分配了一堆堆,并且在退出时不释放它,那么这本身就不是内存泄漏。内存泄漏是指程序在代码段上循环,代码分配堆,然后在不释放堆的情况下"失去跟踪"堆。

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

我唯一要注意的是,在退出时不要释放内存,如果你重构了你的程序,使它成为一个等待输入的服务,不管你的程序做什么,然后循环等待另一个服务调用,那么你所编码的可能会变成内存泄漏。


一方面,我可以指望随着时间的推移,我所看到的"良性"泄漏的数量。

所以答案是非常有资格的是。

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

我已经看到了这种方法,对于那些非常明确的固定计数的事物,例如CPU工作窃取的DEGIs,以及在Hans Boehm的保守的垃圾收集器中保存单元EDOCX1 0状态的缓冲器,用于检测根集等,有很大的好处。

虽然技术上是一个漏洞,但这两种情况在大小上都是有界的,在可增长的循环工作中,窃取deque的情况下,由于队列的内存使用增加了有界因子2,因此有了巨大的性能优势。


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


这是一个非常具体的领域,几乎不值得回答。用你那吓人的脑袋。

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

还有一系列中间情况。

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


在这类问题中,上下文就是一切。就我个人而言,我无法忍受泄密,在我的代码中,如果它们突然出现,我会竭尽全力去修复它们,但修复泄密并不总是值得的,而且当人们按我偶尔告诉他们的小时数向我付款时,我修复它们代码中的泄密并不值得我为此付出代价。让我举个例子:

我正在试验一个项目,做一些性能测试,并修复了许多错误。在应用程序初始化过程中有一个漏洞,我跟踪并完全理解它。正确地修复它需要一天左右的时间来重构一段其他功能代码。我本可以做一些粗制滥造的事情(比如将值填充到一个全局中并抓住某个点,我知道它不再用于释放),但这只会给下一个必须接触代码的人带来更多的混乱。

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

最终,我决定为一个应用程序泄漏150字节,而这个应用程序使用了大约一个千兆的RAM,在一台专用的机器上运行,不值得修复它,所以我写了一条评论说它被泄漏了,需要更改什么来修复它,以及为什么它在当时不值得。


你必须首先意识到感知到的内存泄漏和实际的内存泄漏有很大的区别。通常,分析工具会报告许多红鲱鱼,并将某些东西标记为泄漏(内存或资源,如句柄等),而实际上并非如此。这通常是由于分析工具的体系结构造成的。例如,某些分析工具会将运行时对象报告为内存泄漏,因为它从未看到这些对象被释放。但释放发生在运行时的关闭代码中,分析工具可能看不到该代码。

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

理想的答案是"不,从不"。一个更务实的答案可能是"不,几乎从不"。在现实生活中,你的资源和时间有限,解决问题的时间有限,任务清单也无穷无尽。当其中一项任务是消除内存泄漏时,收益递减规律经常起作用。您可以在一周内消除应用程序中98%的内存泄漏,但剩下的2%可能需要几个月的时间。在某些情况下,甚至不可能消除某些泄漏,因为应用程序的体系结构没有对代码进行重大的重构。你必须权衡消除剩余2%的成本和收益。


虽然大多数答案都集中在真实的内存泄漏上(这永远都不好,因为这是一种草率编码的迹象),但问题的这一部分对我来说似乎更有趣:

What if you allocate some memory and use it until the very last line of code in your application (for example, a global object's deconstructor)? As long as the memory consumption doesn't grow over time, is it OK to trust the OS to free your memory for you when your application terminates (on Windows, Mac, and Linux)? Would you even consider this a real memory leak if the memory was being used continuously until it was freed by the OS.

如果使用了相关的内存,则无法在程序结束之前释放它。自由是由程序退出还是由操作系统完成并不重要。只要这是文档化的,那么更改不会引入真正的内存泄漏,只要图片中没有C++析构函数或C清除函数。未关闭的文件可能通过泄漏的FILE对象显示,但丢失的fclose()也可能导致缓冲区无法刷新。

因此,回到最初的情况,我认为它本身是完全正常的,如此之多,以至于最强大的泄漏探测器之一Valgrind将只在需要时处理此类泄漏。在valgrind上,当您覆盖一个指针而不事先释放它时,它会被视为内存泄漏,因为它更可能再次发生并导致堆无限增长。

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


我很惊讶地看到这么多关于内存泄漏实际上是什么的错误定义。如果没有一个具体的定义,讨论它是否是一件坏事将一事无成。

正如一些评论者正确指出的那样,只有当一个进程分配的内存超出了该进程无法引用或删除的范围时,才会发生内存泄漏。

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

我看不出任何理由允许您自己的代码泄漏,不管它有多小。现代编程语言如C和C++极大地帮助程序员防止这种泄漏,很少有好的理由不采用好的编程技术——特别是当与特定的语言设施结合时——以防止泄漏。

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

可能无法更改或替换现有的(泄漏的)代码,因此您必须接受它。但是,这与声明没事不同。


即使你确信你的"已知"内存泄漏不会造成破坏,也不要这样做。充其量,它将为你在不同的时间和地点犯下类似的、可能更严重的错误铺平道路。

对我来说,问这个问题就像问"早上3点没人在的时候我能闯红灯吗?"当然,在那个时候它可能不会引起任何麻烦,但它会为你在高峰时间做同样的事情提供一个杠杆!


我想,如果你编写的程序是为了泄漏内存(即测试内存泄漏对系统性能的影响),那就没问题了。


I only see one practical disadvantage, and that is that these benign leaks will show up with memory leak detection tools as false positives.

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

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


我不会回答。

理论上,如果你留下一堆乱七八糟的东西,操作系统会在你之后清理干净(现在这只是粗鲁的行为,但是由于电脑没有感觉,这可能是可以接受的)。但是,您不能预测程序运行时可能发生的所有情况。因此(除非您能够对某些行为进行正式的证明),从专业的角度来看,创建内存泄漏是不负责任和草率的。

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


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

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

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

所以,如果你有泄漏,用两种方法评估它的影响

  • 您的软件和用户体验。
  • 对系统(和用户)而言,节省系统资源。
  • 修复对维护和可靠性的影响。
  • 在其他地方引起回归的可能性。
  • 福雷克


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

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


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


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

    我使用的是传统的服务器应用程序,这些应用程序应该是坚如磐石的,但它们存在漏洞,全局应用程序确实妨碍了内存检测工具的使用。这是一件大事。

    在贾里德·戴蒙德的《倒塌》一书中,作者想知道那个人是怎么想的:谁砍掉了复活节岛上的最后一棵树,那棵树是他建造独木舟离开这个岛所需要的。我想知道很多年前,第一个全球性的代码被添加到我们的代码库中的那一天。那是它本该被抓到的日子。


    如果它是有意的,那么它实际上不是一个漏洞,也不是一个问题,除非它有大量的内存,或者可能增长为大量的内存。在程序的生命周期中不清理全局分配是很常见的。如果泄漏是在服务器或长时间运行的应用程序中,随着时间的推移而增长,那么这是一个问题。


    这已经被讨论得很恶心了。底线是内存泄漏是一个bug,必须修复。如果第三方库泄漏内存,会让人怀疑它还有什么问题,不是吗?如果你在造一辆车,你会使用偶尔漏油的发动机吗?毕竟,发动机是别人造的,所以这不是你的错,你修不好,对吧?


    一般来说,如果您有一些您认为无法避免的内存泄漏,那么您需要更仔细地考虑对象所有权。

    但对于你的问题,我的回答简而言之就是生产代码,是的。在开发过程中,不,这看起来可能是向后的,但我的理由是:

    在您描述的情况下,如果内存一直保存到程序结束,那么最好不要释放它。一旦您的进程退出,操作系统就会清理掉。事实上,这可能会让用户的体验更好:在我研究过的一个游戏中,程序员认为在退出之前释放所有内存会更干净,导致程序关闭需要半分钟的时间!一个名为exit()的快速更改使进程立即消失,并将用户放回到他想要的桌面上。

    但是,您对调试工具的看法是正确的:它们会抛出一个fit,并且所有的误报可能会使查找真正的内存泄漏出一个痛苦。因此,总是要编写调试代码来释放内存,并在发送时禁用它。


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

    基辅


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

    对于设计为不退出的服务器程序,您要做什么?

    如果您是那种不设计和实现正确分配和释放资源的代码的程序员,那么我不希望与您或您的代码有任何关系。如果你不想清理你泄露的记忆,那你的锁呢?你把他们也留在外面吗?你把临时文件放在不同的目录里吗?

    泄漏内存并让程序清除?不,绝对不是。这是一个坏习惯,会导致错误、错误和更多的错误。

    自己清理。你妈妈不再在这里工作了。


    是的,内存泄漏可能是两种罪恶中较小的一种。虽然正确性很重要,但是在执行完全内存释放时,系统的性能或稳定性可能会受到影响,释放内存和销毁对象所花的风险和时间可能比退出进程更不可取。

    一般来说,把记忆留在身边通常是不可接受的。很难理解代码将在其中运行的所有作用域,在某些情况下,它可能导致泄漏成为灾难性的。

    What if you allocate some memory and use it until the very last line of code in your application (for example, a global object's destructor)?

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

    is it OK to trust the OS to free your memory for you when your application terminates

    当短期程序创建大型C++集合(例如std::map集合)时,每个对象至少有2个分配。通过这个集合迭代来销毁对象需要CPU实时处理,并且让对象泄漏并由操作系统整理,具有性能优势。计数器,是否存在一些未被操作系统整理的资源(例如共享内存),如果不销毁代码中的所有对象,则可能会有一些资源占用这些未释放的资源的风险。

    What if a third party library forced this situation on you?

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

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

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

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

    如果操作系统即将关闭,所有资源都将被清理干净。不执行正常进程关闭的好处是,用户在关闭时获得更快速的性能。

    破碎的物体

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

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

    检漏员误报

    一些泄漏检查程序通过检测对象来工作,其行为方式与全局检查程序相同。它们有时会错过另一个全局对象有一个有效的析构函数,在它们完成后调用,这将释放内存。


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

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


    我完全同意johnmcg的观点,只是想补充一下,我自己在及时发现真正的、潜在的严重的记忆泄漏方面遇到了问题,仅仅是因为它被认为是良性的。随着时间的推移,当它们变得如此之多时,在良性的洪水中发现严重的洪水就变得越来越困难。

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


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

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

    退出应用程序的好处:

  • 操作系统获得一个块来释放,而不是许多小块。这意味着关闭要快得多。尤其是在内存管理很慢的Windows上。
  • 退出的坏处实际上是两点:

  • 很容易忘记释放操作系统没有跟踪的资源,或者操作系统可能会等待一点释放。TCP套接字就是一个例子。
  • 内存跟踪软件会将出口未释放的所有内容报告为泄漏。
  • 因此,您可能需要两种关闭模式,一种是快速关闭,另一种是脏关闭,供最终用户使用,另一种是缓慢关闭,供开发人员使用。一定要同时测试两个:)


    我在C上的高中上了一节课,老师说当你malloc的时候一定要释放。

    但当我上另一所大学的时候,教授说,不为那些只运行一秒钟的小项目免费是可以的。所以我认为这不会影响你的程序,但是免费提供强大、健康的代码是一个好的实践。


    你对"内存泄漏"的定义是"我不清理自己的内存",所有现代操作系统都会在程序退出时释放它。但是,由于这是一个C++问题,您可以简单地将内存中的问题封装在一个适当的EDCOX1(1)中,当它超出范围时将调用删除。


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

    这是一个非常简单的规则……以不泄漏为目的进行编程,可以很容易地发现新的泄漏。你会卖给别人一辆你自己造的车吗?因为你知道它每次熄火时都会在地上喷溅汽油。:)

    如果清除函数中的()free()调用很便宜,为什么不使用它们呢?


    考虑到应用程序稍后会从另一个应用程序中使用,有可能在单独的窗口中或在彼此之后打开其中几个应用程序来执行某些操作。如果它不是运行一个进程,而是作为一个库,那么调用程序会泄漏内存,因为您认为冷跳过了内存清理。

    使用某种智能指针自动为您执行此操作(例如,boost libs中的作用域指针)


    一段时间前,我会说是的,有时候让程序中的一些内存泄漏(它仍然是快速原型)是可以接受的,但现在已经有了5到6倍的经验,即使是最轻微的泄漏也会发现一些真正严重的功能错误。当数据实体的生命周期不为人所知时,程序就会出现漏洞,这表明缺乏分析。总之,知道程序中发生了什么总是一个好主意。


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

    当你有一个长期运行的程序,并且用户依赖它时,问题就会出现。另外,让内存泄漏存在于您的程序中也是一个糟糕的编码习惯,尤其是在工作中,如果有一天它们可能会将代码转换成其他代码的话。

    总之,清除内存泄漏更好。


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


    也许是一针见血:如果你的应用程序在Unix上运行,可能会变成僵尸呢?在这种情况下,操作系统不会回收内存。所以我说你真的应该在程序退出之前取消分配内存。


    不,它们没有问题,但是我已经实现了一些分配器、内存转储程序和泄漏检测器,并且发现作为一个实用的问题,允许将这样的分配标记为"就泄漏报告而言不是泄漏"是很方便的……

    这有助于使泄漏报告更有用…不拥挤"静态范围内的动态分配不自由"由程序退出


    如果在main()的尾部之前一直使用它,那么它根本不是一个泄漏(当然,假设有一个受保护的内存系统!).

    实际上,在进程关闭时释放对象绝对是最糟糕的事情…操作系统必须在您所创建的每个页面中重新分页。当然,关闭文件句柄、数据库连接,但是释放内存是愚蠢的。


    只有一个例子:由于一个不可恢复的错误,程序将要自己拍摄。


    只要您的内存利用率不随时间增加,这取决于。如果您在服务器软件中执行了大量复杂的同步,比如启动在系统调用上阻塞的后台线程,那么执行干净的关闭可能太复杂,不合理。在这种情况下,替代方案可能是:

  • 在进程退出之前不会清除其内存的库。
  • 您可以编写额外的500行代码,并向类中添加另一个互斥体和条件变量,这样它就可以从测试中完全关闭——但在生产环境中永远不会使用此代码,在生产环境中,服务器只会因崩溃而终止。

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


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


    如果您的代码有任何内存泄漏,甚至是已知的"可接受"泄漏,那么您将有一段烦人的时间使用任何内存泄漏工具来查找您的"真正"泄漏。就像留下"可接受的"编译器警告一样,发现新的"真实的"警告更加困难。