在C或C ++应用程序中使用memory leak是否可以接受?
如果您分配一些内存并使用它直到应用程序中最后一行代码(例如,全局对象的析构函数),该怎么办?只要内存消耗不会随着时间的推移而增长,当您的应用程序终止时(在Windows,Mac和Linux上),是否可以信任操作系统为您释放内存?如果内存被持续使用,直到它被操作系统释放,你甚至会认为这是一个真正的内存泄漏。
如果第三方图书馆强迫你这样做怎么办?无论它有多么伟大,都会拒绝使用第三方库吗?
我只看到一个实际的缺点,那就是这些良性泄漏会将内存泄漏检测工具显示为误报。
答案 0 :(得分:321)
没有
作为专业人士,我们不应该问自己的问题是,“这样做是否可行?”而是“有没有好理由这样做?”而“追捕内存泄漏是一种痛苦”并不是一个好理由。
我喜欢简单易懂。简单的规则是我的程序应该没有内存泄漏。
这也让我的生活变得简单。如果我检测到内存泄漏,我会消除它,而不是通过一些精心设计的决策树结构来确定它是否是“可接受的”内存泄漏。
它类似于编译器警告 - 警告对我的特定应用程序是否致命?也许不吧。
但这最终是专业纪律的问题。容忍编译器警告和容忍内存泄漏是一种坏习惯,最终会让我陷入困境。
为了将事情发挥到极致,外科医生是否可以将某些操作设备留在患者体内?
虽然有可能出现这样一种情况,即移除该设备的成本/风险超过了将其丢弃的成本/风险,并且可能存在无害的情况,如果我看到这个问题发布在SurgeonOverflow.com并看到除“不”之外的任何答案,这将严重损害我对医学界的信心。
-
如果第三方图书馆强迫我这样做,那将导致我严重怀疑图书馆的整体质量。这就好像我试驾开车,在其中一个杯架中发现了一些松散的垫圈和螺母 - 这本身可能不是什么大问题,但它描述了对质量缺乏承诺,所以我会考虑替代品。
答案 1 :(得分:80)
除非“使用”的内存量不断增长,否则我不认为它是内存泄漏。除非所需的内存量不断增长,否则有一些未发布的内存虽然不理想但不是一个大问题。
答案 2 :(得分:78)
首先让我们的定义正确。内存泄漏是动态分配内存的时间,例如malloc()
,并且所有对内存的引用都会丢失而没有相应的空闲内存。制作一个的简单方法是这样的:
#define BLK ((size_t)1024)
while(1){
void * vp = malloc(BLK);
}
注意,每次while(1)循环,分配1024(+开销)字节,并将新地址分配给vp;没有剩余的指针指向前面的malloc'ed块。保证该程序运行直到堆耗尽,并且无法恢复任何malloc内存。内存正在“泄漏”,永远不会被再次看到。
你所描述的,听起来像是
int main(){
void * vp = malloc(LOTS);
// Go do something useful
return 0;
}
您分配内存,使用它直到程序终止。这不内存泄漏;它不会损害程序,当程序终止时,所有内存都会自动清除。
通常,您应该避免内存泄漏。首先,因为像你上面的高度和机库的燃料一样,泄漏并且无法恢复的记忆是无用的;第二,在开始时正确编码,而不是泄漏内存比在以后发现内存泄漏要容易得多。
答案 3 :(得分:39)
理论上没有,在实践中取决于。
这实际上取决于程序正在处理多少数据,程序运行的频率以及程序是否持续运行。
如果我有一个快速程序读取少量数据进行计算并退出,则永远不会注意到小内存泄漏。因为程序运行时间很长而且只使用少量内存,所以当程序存在时,泄漏会很小并且会被释放。
另一方面,如果我有一个程序可以处理数百万条记录并长时间运行,那么在有足够时间的情况下,小内存泄漏可能会导致机器停机。
对于有泄漏的第三方库,如果它们导致问题,要么修复库,要么找到更好的替代方案。如果它没有引起问题,它真的重要吗?
答案 4 :(得分:36)
许多人似乎认为,一旦你释放内存,它就会立即返回到操作系统,并可以被其他程序使用。
事实并非如此。操作系统通常以4KiB页面管理存储器。 malloc
和其他类型的内存管理从操作系统获取页面,并在他们认为合适时对其进行子管理。 free()
很可能不将页面返回到操作系统,假设您的程序稍后将使用更多的内存。
我并不是说free()
永远不会将内存返回给操作系统。它可能会发生,特别是如果你释放大量的内存。但是没有保证。
重要的事实:如果您没有释放不再需要的内存,则可以保证进一步的malloc消耗甚至更多的内存。但如果你先释放,malloc可能会重新使用释放的内存。
这在实践中意味着什么?这意味着如果你知道你的程序从现在开始不需要更多的内存(例如它在清理阶段),释放内存并不是那么重要。但是,如果程序稍后可能会分配更多内存,则应避免内存泄漏 - 尤其是可能重复发生的内存泄漏。
另请参阅this comment,了解有关在终止错误之前释放内存的原因的详细信息。
评论者似乎并不理解调用free()
不会自动允许其他程序使用释放的内存。但这就是这个答案的全部要点!
所以,为了说服人们,我将展示一个例子,其中free()没有什么好处。为了使数学易于理解,我将假装操作系统以4000字节页面管理内存。
假设您分配了一万个100字节的块(为简单起见,我将忽略管理这些分配所需的额外内存)。这消耗1MB或250页。如果随后随机释放了9000个这样的块,那么你只剩下1000块 - 但它们遍布整个地方。据统计,大约有5个页面是空的。其他245将分别具有至少一个分配的块。这相当于980KB的内存,操作系统无法回收 - 即使你现在只分配了100KB!
另一方面,你现在可以在不增加你的程序占用的内存量的情况下malloc()9000多个块。
即使free()
技术上 将内存返回给操作系统,也可能不会。 free()
需要在快速操作和节省内存之间取得平衡。此外,已经分配了大量内存然后释放它的程序可能会再次这样做。 Web服务器需要在请求后请求后处理请求 - 保留一些“松弛”内存是有意义的,这样您就不需要一直向操作系统询问内存。
答案 5 :(得分:27)
在运行应用程序后清除os是没有概念上的错误。
这实际上取决于应用程序及其运行方式。需要运行数周的应用程序中不断出现的泄漏必须得到解决,但是一个计算结果而不需要太高内存需求的小工具应该不是问题。
有许多脚本语言不会垃圾收集循环引用的原因......对于它们的使用模式,它不是一个实际问题,因此与浪费的内存一样浪费资源。
答案 6 :(得分:19)
我相信答案是否定的,绝不允许内存泄漏,我有几个原因,我没有看到明确说明。这里有很好的技术答案,但我认为真正的答案取决于更多的社会/人类原因。
(首先,请注意,正如其他人所提到的,真正的泄漏是当你的程序在任何时候都失去了它已经分配的内存资源的跟踪。在C中,当你malloc()
指针时会发生这种情况。让指针离开范围而不先执行free()
。)
你决定的重要关键是习惯。当你用一种使用指针的语言进行编码时,你将会使用指针很多。指针很危险;它们是向代码中添加各种严重问题的最简单方法。
当你编码时,有时候你会在球上,有时你会感到疲倦,生气或担心。在那些有点分心的时候,你在自动驾驶仪上编码更多。 自动驾驶效果无法区分一次性代码和较大项目中的模块。在这段时间内,您建立的习惯将最终落入您的代码库中。
所以不,永远不要让内存泄漏的原因与你在更换车道时仍应检查盲点的原因相同,即使你现在是路上唯一的车。 在你的活跃大脑分散注意力的时候,良好的习惯可以帮助你避免灾难性的失误。
除了“习惯”问题之外,指针很复杂,通常需要大量的脑力才能在心理上进行跟踪。当你使用指针时,最好不要“浑水”,特别是当你刚接触编程时。
还有更多的社交方面。通过正确使用malloc()
和free()
,任何查看代码的人都会感到轻松自在;你正在管理你的资源。但是,如果不这样做,他们会立即怀疑问题。
也许你已经知道内存泄漏在这种情况下不会伤害任何东西,但是当你读取那段代码时,代码的每个维护者都必须在脑子里工作。 / strong>使用free()
即表示您无需考虑问题。
最后,编程是将一个过程的心理模型写成一种明确的语言,这样一个人和一台计算机就能完全理解所述过程。 优秀编程实践的一个重要部分是永远不会引入不必要的歧义。
智能编程灵活且通用。错误的编程很模糊。
答案 7 :(得分:15)
我认为在你的情况下答案可能是没关系。但你肯定需要记录内存泄漏是一个有意识的决定。您不希望维护程序员出现,将您的代码插入函数内,并将其调用一百万次。因此,如果您决定泄漏是可以的,那么您需要为将来可能需要参与该计划的任何人记录(大写字母)。
如果这是第三方库,您可能会被困。但绝对可以证明这种泄漏发生了。
但基本上如果内存泄漏是一个已知的数量,如512 KB缓冲区或其他什么,那么这是一个非问题。如果内存泄漏持续增长,就像每次调用库调用时,内存增加512KB并且没有释放,那么您可能会遇到问题。如果您记录并控制呼叫执行的次数,则可以进行管理。但是你真的需要文档,因为虽然512并不多,但是有超过一百万次调用512次。
您还需要检查操作系统文档。如果这是一个嵌入式设备,可能会有一些操作系统无法从退出的程序中释放所有内存。我不确定,也许这不是真的。但值得研究。
答案 8 :(得分:14)
我会给出一个不受欢迎但实际的答案,即释放内存总是错误总是错误的,除非这样做会减少程序的内存使用量。例如,一个程序进行单个分配或一系列分配以加载它将在其整个生命周期中使用的数据集,而不需要释放任何东西。在一个具有非常动态内存要求的大型程序(想想一个Web浏览器)的更常见的情况下,你应该尽快释放你不再使用的内存(例如关闭标签/文档/等)。 ,但是当用户选择点击“退出”时,没有理由释放任何内容,这样做实际上对用户体验有害。
为什么呢?释放内存需要触摸内存。即使你的系统的malloc实现没有在分配的内存块附近存储元数据,你也可能会走向递归结构,只是为了找到你需要释放的所有指针。
现在,假设您的程序使用了大量数据,但暂时没有触及大部分数据(同样,Web浏览器就是一个很好的例子)。如果用户正在运行大量应用程序,那么很大一部分数据可能已交换到磁盘。如果您只是退出(0)或从主页返回,它会立即退出。出色的用户体验。如果您在尝试释放所有内容时遇到麻烦,您可能会花费5秒或更长时间将所有数据交换回来,然后立即将其丢弃。浪费用户的时间。浪费笔记本电脑的电池寿命。浪费在硬盘上的磨损。
这不仅仅是理论上的。每当我发现自己加载的应用程序太多并且磁盘开始颠簸时,我甚至不会考虑单击“退出”。我尽可能快地到达终端并键入killall -9 ...因为我知道“退出”会让情况变得更糟。
答案 9 :(得分:11)
我确信有人可以说出是的理由,但不会是我。 而不是拒绝,我会说这不应该是一个是/否的问题。 有办法管理或包含内存泄漏,许多系统都有它们。
在离开地球的设备上有NASA系统可以为此做出规划。系统将每隔一段时间自动重启,以便内存泄漏不会对整个操作造成致命的影响。只是遏制的一个例子。
答案 10 :(得分:8)
如果您分配内存并使用它直到程序的最后一行,那不是泄漏。如果您分配内存并忘记它,即使内存量没有增长,这也是一个问题。分配但未使用的内存可能会导致其他程序运行速度变慢或根本不运行。
答案 11 :(得分:8)
如果在程序开头分配了一堆堆,并且在退出时没有释放它,那本身就不是内存泄漏。内存泄漏是指你的程序循环遍历一段代码,并且该代码分配堆然后“丢失跟踪”它而不释放它。
实际上,在退出之前无需调用free()或delete。当进程退出时,操作系统会回收所有内存(POSIX就是这种情况。在其他操作系统上 - 尤其是嵌入式操作系统 - YMMV)。
我在退出时没有释放内存的唯一警告是,如果你重构你的程序,以便它,例如,成为一个等待输入的服务,无论你的程序做什么,然后循环等待另一个服务调用,然后您编码的内容会变成内存泄漏。
答案 12 :(得分:8)
我一方面可以指望一段时间以来我所见过的“良性”泄漏的数量。
所以答案是非常合格的。
一个例子。如果你有一个单例资源,需要一个缓冲区来存储一个循环队列或双端队列,但不知道缓冲区需要多大,并且无法承担锁定或每个读取器的开销,那么分配一个指数倍增的缓冲区但是不释放旧的会泄漏每个队列/双端队列的大量内存。这些的好处是它们可以显着加快每次访问的速度,并且可以通过永远不存在争用锁定的风险来改变多处理器解决方案的渐近性。
我已经看到这种方法非常有利于具有非常明确的计数的事物,例如每CPU工作窃取deques,以及用于保持单/proc/self/maps
状态的缓冲区的程度小得多在Hans Boehm用于C / C ++的保守垃圾收集器中,用于检测根集等。
虽然从技术上来说是泄密,但这两种情况都是有限的,并且在可成长的循环工作窃取案件中,有一个巨大的性能胜利,以换取内存增加2倍的有限因素队列的用法。
答案 13 :(得分:6)
这是特定领域的,几乎不值得回答。用你的头脑。
并且存在一系列中间情况。
延迟产品发布以解决除了最糟糕的内存泄漏之外的所有机会成本($$$)通常使任何“草率或不专业”的感觉相形见绌。你的老板付钱让你为他赚钱,而不是为了得到温暖,模糊的感情。答案 14 :(得分:5)
虽然大多数答案都集中在真正的内存泄漏上(因为它们是编码草率的标志),但这部分问题对我来说更有趣:
如果你分配一些内存并使用它直到应用程序中最后一行代码(例如,全局对象的解构函数),该怎么办?只要内存消耗不会随着时间的推移而增长,当您的应用程序终止时(在Windows,Mac和Linux上),是否可以信任操作系统为您释放内存?如果内存被持续使用,直到它被操作系统释放,你甚至会认为这是一个真正的内存泄漏。
如果使用了相关的内存,则无法在程序结束前释放它。免费是由程序退出还是由操作系统完成无关紧要。只要记录了这一点,那么更改不会引入真正的内存泄漏,并且只要图片中没有涉及C ++析构函数或C清理函数。可能通过泄漏的FILE
对象显示未关闭的文件,但缺少fclose()也可能导致缓冲区无法刷新。
所以,回到原来的情况,恕我直言就完全没问题了,Valgrind是最强大的泄漏探测器之一,只有在要求的情况下才会对这种泄漏进行处理。在Valgrind上,当你在不事先释放它的情况下覆盖指针时,它会被视为内存泄漏,因为它更有可能再次发生并导致堆无限增长。
然后,没有可以访问的nfreed内存块。人们可以确保在出口处释放所有这些,但这本身就是浪费时间。关键是他们可以在之前释放。在任何情况下,降低内存消耗都很有用。
答案 15 :(得分:5)
在这种问题中,背景就是一切。我个人无法忍受泄漏,在我的代码中,如果他们突然出现,我会竭尽全力修复它们,但是修复泄漏并不总是值得的,当人们按小时付钱给我时,我偶尔会他告诉他们,在我们的代码中修复漏洞并不值得我付费。让我举个例子:
我正在对一个项目进行分类,做一些工作并修复很多错误。在我跟踪并完全理解的应用程序初始化期间发生了泄漏。正确修复它需要一天左右的时间来重构一段功能正常的代码。我本可以做一些hacky(比如将值填充到全局并抓住它,我知道它已经不再用于释放了),但这会让下一个不得不触摸代码的人感到更加困惑。
就个人而言,我不会首先编写代码,但我们大多数人都不会总是使用原始设计良好的代码库,有时你必须务实地看待这些事情。修复150字节泄漏所花费的时间可以用来进行算法改进,从而减少兆字节的内存。
最终,我决定泄漏150个字节的应用程序使用大约一个ram并在专用机器上运行并不值得修复它,所以我写了一条评论说它被泄露了,需要改变的是什么为了解决它,以及为什么它当时不值得。
答案 16 :(得分:5)
您必须首先意识到感知内存泄漏与实际内存泄漏之间存在很大差异。非常频繁的分析工具会报告许多红色鲱鱼,并将某些东西标记为泄漏(内存或资源,如手柄等)实际上并非如此。通常这是由于分析工具的架构。例如,某些分析工具会将运行时对象报告为内存泄漏,因为它永远不会看到这些对象被释放。但是重新分配发生在运行时的关闭代码中,分析工具可能无法看到它。
话虽如此,仍有时候你会发现实际的内存泄漏很难找到或很难修复。所以现在问题变成是将它们留在代码中了吗?
理想的答案是,“不,永远不会。”一个更务实的答案可能是“不,几乎从不”。在现实生活中,您经常需要有限的资源和时间来解决无尽的任务列表。当其中一项任务是消除内存泄漏时,收益递减规律经常会发挥作用。您可以在一周内消除98%的应用程序内存泄漏,但剩下的2%可能需要数月。在某些情况下,由于应用程序的架构没有重大的代码重构,甚至可能无法消除某些泄漏。您必须权衡消除剩余2%的成本和收益。
答案 17 :(得分:3)
即使您确定“已知”的内存泄漏不会造成严重破坏,也不要这样做。充其量,它将为您在不同的时间和地点制造类似且可能更严重的错误铺平道路。
对我来说,问这就像质疑“我可以在早上凌晨3点打破红灯,当时没有人在身边?”当然,它可能不会造成任何麻烦,但它会为你在高峰时段做同样的事情提供杠杆!
答案 18 :(得分:3)
我想如果您正在编写一个旨在泄漏内存的程序(即测试内存泄漏对系统性能的影响),那就没问题了。
答案 19 :(得分:2)
我只看到一个实际的缺点,那就是这些良性泄漏会将内存泄漏检测工具显示为误报。
如果我理解正确,你就不会明确地释放内存(因为你还有一个指针可以释放它)并依赖操作系统在进程终止期间释放它。虽然这对简单程序来说似乎没什么问题,但请考虑将代码移入库并成为24/7运行的驻留守护进程的一部分的情况。假设这个守护进程每次需要使用你的代码做一些有用的事情时产生一个线程,并说它每小时产生数千个线程。在这种情况下,您将获得真正的内存泄漏。
不幸的是,这种情况在现实生活中并非不可能,而且一致的内存管理技术可能会让您的生活更轻松。
答案 20 :(得分:2)
不,您不应该有操作系统为您清理的泄漏。原因(在我上面的答案中没有提到我可以检查)是你永远不会知道当你的main()将被重新用作另一个程序中的函数/模块。如果你的main()成为另一个人的软件中经常被调用的函数 - 这个软件会有内存泄漏,随着时间的推移会占用内存。
KIV
答案 21 :(得分:2)
我会回答否。
从理论上讲,操作系统会在您离开后弄清楚(现在这只是粗鲁,但由于计算机没有感觉,因此可以接受)。但是,您无法预测程序运行时可能出现的每种情况。因此(除非你能够对某些行为进行正式证明),从专业角度来看,造成内存泄漏是不负责任和草率的。
如果第三方组件泄露内存,这是一个非常强烈的反对使用它的论据,不仅因为它即将产生影响,而且还因为它表明程序员工作不稳定,这也可能影响其他指标。现在,在考虑遗留系统时,这很困难(考虑网页浏览组件:据我所知,他们所有泄漏内存)但它应该是常态。
答案 22 :(得分:2)
作为一般规则,如果你有内存泄漏,你觉得你无法避免,那么你需要更加思考对象所有权。
但是对于你的问题,我的答案简而言之是在生产代码中,是的。在开发过程中,没有。这似乎是倒退,但这是我的理由:
在你描述的情况下,内存一直持有到程序结束,完全可以不释放它。一旦您的流程退出,操作系统仍会进行清理。事实上,它可能会让用户体验更好:在我参与过的游戏中,程序员认为在退出之前释放所有内存会更加清晰,导致程序关闭需要半分钟!一个名为exit()的快速更改使该过程立即消失,并将用户放回到他想要的桌面。
然而,你对调试工具是正确的:他们会抛出一个合适的,所有的误报可能会让你找到真正的内存泄漏。因此,总是编写释放内存的调试代码,并在发货时禁用它。
答案 23 :(得分:2)
它真的不是泄漏,如果它是有意的,它不是一个问题,除非它有大量的内存,或者可能会成长为大量的内存。在程序的生命周期内不清除全局分配是相当常见的。如果泄漏在服务器或长时间运行的应用程序中,随着时间的推移而增长,则问题就出现了。
答案 24 :(得分:2)
我想你已回答了自己的问题。最大的缺点是它们如何干扰内存泄漏检测工具,但我认为这种缺点对某些类型的应用程序来说是一个巨大的缺点。
我使用遗留服务器应用程序,这些应用程序应该是坚如磐石的,但它们有漏洞,全局变量会妨碍内存检测工具。这是一个大问题。
在杰瑞德·戴蒙德的“崩溃”一书中,作者想知道这个家伙在减少复活节岛上最后一棵树的想法,这棵树是为了建造一艘独木舟离开这座岛而需要的。我很想知道很多年前第一个全局被添加到我们的代码库中的那一天。那天应该被抓住了。
答案 25 :(得分:2)
通常,独立应用程序中的内存泄漏并不是致命的,因为它会在程序退出时被清除。
如何设计的服务器程序不会退出?
如果您是那种不设计和实现资源分配和正确发布的代码的程序员,那么我不希望与您或您的代码有任何关系。如果你不在乎清理泄露的内存,你的锁怎么样?你还把它们挂在那里吗?你是否在各种目录中留下了很少的临时文件?
泄漏内存并让程序清理它?不,绝对不是。这是一个坏习惯,会导致错误,错误和更多错误。
自己清理干净。哟妈妈不再在这里工作了。
答案 26 :(得分:2)
已经讨论过ad nauseam。底线是内存泄漏是一个错误,必须修复。如果第三方库泄漏内存,它会让人怀疑它还有什么问题,不是吗?如果你正在制造汽车,你会使用偶尔漏油的发动机吗?毕竟,其他人制造引擎,所以这不是你的错,你无法解决它,对吗?
答案 27 :(得分:2)
我看到的问题与所有这样的场景问题一样:当程序发生变化时会发生什么,突然发现内存泄漏很少被调用一千万次,而程序结束时则处于不同的位置,所以它确实重要?如果它在库中,那么记录库维护者的错误,不要在你自己的代码中泄漏。
答案 28 :(得分:2)
从历史上看,它在某些边缘情况下对某些操作系统很重要。这些边缘情况将来可能存在。
这是一个例子,在Sun 3时代的SunOS上,如果一个进程使用了exec(或者更传统的fork然后是exec),则存在一个问题,后续的新进程将继承与父进程相同的内存占用不要缩水。如果父进程分配了1/2 gig的内存并且在调用exec之前没有释放它,则子进程将开始使用相同的1/2 gig(即使它没有被分配)。 SunTools(他们的默认窗口系统)最好地展示了这种行为,这是一个内存耗尽。它产生的每个应用程序都是通过fork / exec创建的,并继承了SunTools的足迹,迅速填补了交换空间。
答案 29 :(得分:2)
我同意vfilby - 这取决于。在Windows中,我们将内存泄漏视为相对严重的错误。但是,它在很大程度上取决于组件。
例如,对于运行很少且在有限时间内运行的组件,内存泄漏并不严重。这些组件运行,执行theire工作,然后退出。当他们退出时,他们的内存被隐含地释放。
但是,服务或其他长期运行组件(如shell)中的内存泄漏非常严重。原因是随着时间的推移,这些错误会“窃取”内存。恢复此功能的唯一方法是重新启动组件。大多数人不知道如何重新启动服务或shell - 所以如果他们的系统性能受损,他们只是重新启动。
所以,如果你有泄漏 - 用两种方式评估其影响
Foredecker
答案 30 :(得分:1)
看起来你对“内存泄漏”的定义是“我不会清理自己的记忆”。所有现代操作系统都将在程序退出时释放它。但是,由于这是一个C ++问题,您可以简单地将相关内存包装在适当的std::auto_ptr
内,当它超出范围时将调用delete。
答案 31 :(得分:1)
这实际上取决于创建内存泄漏的对象的用法。 如果您在使用该对象的应用程序的生命周期中多次创建该对象,则使用该方法是不好的。因为存在大量内存泄漏。 另一方面,如果我们有一个对象实例而没有消耗内存而只是少量泄漏那么这不是问题。
当应用程序运行时泄漏增加时,内存泄漏是一个问题。
答案 32 :(得分:1)
当应用程序关闭时,可以说最好不要释放内存。
理论上,操作系统应该释放应用程序使用的资源,但总有一些资源是此规则的例外。所以要小心。
退出应用程序的好处:
刚退出的坏事实际上是两点:
因此,您可能希望有两种关闭模式,一种是针对最终用户的快速和脏,另一种是针对开发人员的缓慢和彻底的模式。只需确保测试两者:)
答案 33 :(得分:1)
Yes a memory leak can be the lesser of two evils. Whilst correctness is important, the performance, or the stability of the system can be impacted when performing full memory release, and the risks and time spent freeing memory and destroying objects may be less desirable than just exiting a process.
In general, it is not usually acceptable to leave memory around. It is difficult to understand all of the scopes which your code will run in, and in some cases, it can result in the leak becoming catastrophic.
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)?
In this case, your code may be ported within a larger project. That may mean the lifetime of your object is too long (it lasts for the whole of the program, not just the instance where it is needed), or that if the global is created and destroyed, it would leak.
is it OK to trust the OS to free your memory for you when your application terminates
When a short lived program creates large C++
collections (e.g. std::map
), there are at least 2 allocations per object. Iterating through this collection to destroy the objects takes real time for the CPU, and leaving the object to leak and be tidied up by the OS, has performance advantages. The counter, is there are some resources which are not tidied by the OS (e.g. shared memory), and not destroying all the objects in your code opens the risk that some held onto these non-freed resources.
What if a third party library forced this situation on you?
Firstly I would raise a bug for a close
function which freed the resources. The question on whether it is acceptable, is based on whether the advantages the library offers (cost, performance, reliability) is better than doing it with some other library, or writing it yourself.
In general, unless the library may be re-initialized, I would probably not be concerned.
If the operating system is about to be turned off, all resources will be tidied up. The advantage of not performing normal process shutdown, is the user gets a snappier performance when turning off.
Within my past, we found an object (and raised a defect for that team), that if they crashed at certain points, they became broken, that all of the subsequent functions in that object would result in a hang.
Whilst it is poor practice to ignore the memory leak, it was more productive to shutdown our process, leaking the object and its memory, than to result in a hang.
Some of the leak checkers work by instrumenting objects, and behaving in the same way as globals. They can sometimes miss that another global object has a valid destructor, called after they finish which would release the memory.
答案 34 :(得分:1)
我完全赞同JohnMcG,并且只是想补充一点,我自己有问题要及时发现真正的,可能严重的内存泄漏,只是因为已经接受了良性的泄漏。随着时间的推移,这些已经变得如此之多,在良性洪水中发现严重的那些变得越来越困难。
至少对于你的同事们来说(以及将来对你自己而言),请尽快给他们做好准备。
答案 35 :(得分:1)
我在C高中上了一节课,老师说当你在malloc时总是要自由。
但是当我上了另一门课程的时候,教授说没有免费试用只运行一秒钟的小型课程。 所以我认为它不会伤害你的程序,但是为了获得强大,健康的代码是免费的。
答案 36 :(得分:0)
这里有一些很棒的答案。为了向这个问题添加另一个视角,我将解决内存泄漏不仅可以接受但理想的情况:在Windows驱动程序环境中,开发人员提供了一组回调,在需要时由操作系统运行。其中一个回调是'Shutdown'回调,它在系统关闭/重启之前运行。与标准情况不同,不仅不需要内存释放(系统将在一瞬间关闭),甚至不鼓励 - 尽可能快地关闭并防止内存管理的开销。
答案 37 :(得分:0)
规则很简单:如果你完成了一些内存清理它。 有时即使我们稍后需要一些实例,但我们注意到我们大量使用内存,因此它会因为交换到磁盘而影响性能,我们可以将数据存储到磁盘中的文件中并在重新加载后,有时这种技术可以优化你的程序很多
答案 38 :(得分:0)
考虑一下该应用程序稍后从另一个应用程序中使用的情况,可以在单独的窗口中打开它们,或者在彼此之后打开它们。如果它没有运行一个进程,而是作为一个库,那么调用程序会泄漏内存,因为你认为你冷却了内存清理。
使用某种自动为你做的智能指针(例如来自Boost libs的scoped_ptr)
答案 39 :(得分:0)
前段时间我会说是的,在你的程序中让某些内存泄漏(它仍在进行快速原型设计)有时是可以接受的,但现在已经达到了5到6倍的跟踪即使泄漏最少的泄漏一些非常严重的功能错误。当数据实体的生命周期不是真正已知时,让程序中的泄漏发生,显示缺乏分析。总而言之,了解程序中发生的事情总是一个好主意。
答案 40 :(得分:0)
我相信如果你有一个程序可以运行几秒钟然后退出并且它仅供个人使用,那也没关系。一旦程序结束,任何内存泄漏都将被清除。
当你有一个程序运行一段时间并且用户依赖它时,就会出现问题。如果你的程序有一天可能会将代码变成别的东西,那么你的程序中存在内存泄漏也是一种糟糕的编码习惯。
总而言之,它可以更好地消除内存泄漏。
答案 41 :(得分:0)
在程序的最后一行省略释放内存是完全可以接受的,因为释放它对任何事都没有影响,因为程序永远不需要记忆。
答案 42 :(得分:0)
分裂头发可能:如果你的应用程序在UNIX上运行并且可以变成僵尸怎么办?在这种情况下,操作系统不会回收内存。所以我说你真的应该在程序退出之前取消分配内存。
答案 43 :(得分:0)
不,他们不行,但是我已经实现了一些分配器,内存翻转器和泄漏检测器,并且发现作为一个实用的问题,允许人们将这样的分配标记为“Not”很方便就泄漏报告而言,泄漏是“ ......
这有助于使泄漏报告更有用......并且没有“在静态范围内动态分配而不是程序退出免费”
答案 44 :(得分:0)
如果您的代码有任何内存泄漏,即使已知的“可接受”泄漏,那么使用任何内存泄漏工具来查找“真正的”泄漏都会有烦人的时间。就像留下“可接受的”编译器警告一样,使得发现新的“真实”警告变得更加困难。
答案 45 :(得分:0)
如果你使用它直到main()
的尾部,它根本就不是泄漏(当然假设受保护的内存系统!)。
事实上,在进程关闭时释放对象是您可以做的绝对最差事情......操作系统必须在您回溯的每个页面中回页。关闭文件句柄,数据库连接,当然,但释放内存是愚蠢的。
答案 46 :(得分:0)
最佳做法是始终释放您分配的内容,特别是在编写旨在在系统的整个正常运行时间内运行的内容时,即使在退出之前进行清理时也是如此。
这是一个非常简单的规则..编程的目的是没有泄漏,这使得新泄漏很容易发现。你会不会向某人开卖一辆汽车,因为它知道它在关闭时会在地面上溅出气体? :)
清理函数中的一些if()free()调用很便宜,为什么不使用它们呢?
答案 47 :(得分:0)
仅在一个实例中:由于不可恢复的错误,程序将自行开枪。
答案 48 :(得分:0)
只要您的内存利用率不会随着时间的推移而增加,这取决于。如果您在服务器软件中进行了大量复杂的同步,比如启动阻止系统调用的后台线程,那么执行干净关闭可能过于复杂而无法证明。在这种情况下,替代方案可能是: