不释放内存是否可以接受

时间:2009-01-30 17:51:34

标签: c++ c oop memory-management memory-leaks

我正在开发一个应该从命令行使用的项目,语法如下:

program-name input-file

该程序应该处理输入,计算一些东西并在stdout上吐出结果。

我选择的语言是C ++,原因有几个,我不愿意辩论。计算阶段将是高度符号化的(思考编译器),并将使用非常复杂的动态分配数据结构。特别是,它不适合RAII风格的编程。

我想知道忘记释放内存是否可以接受,因为我希望整个计算消耗的内存少于可用内存,并且程序完成后OS可以在一步中自由回收所有内存(假设程序在几秒钟内终止)。你对此有何感想?

作为备份计划,如果我的项目需要以服务器或交互方式运行,我想我总是可以将垃圾收集器重新编译为源代码。有没有人有使用C ++垃圾收集器的经验?它们运作良好吗?

19 个答案:

答案 0 :(得分:22)

在描述问题的具体情况下不应引起任何问题。

然而,这并不完全正常。静态分析工具会抱怨它。最重要的是,它会制造坏习惯。

答案 1 :(得分:15)

有时不会释放内存是正确的。

我曾经写过编译器。在构建解析树并遍历它以编写中间代码之后,我们只需退出。解除分配树会有

  • 给编译器增加了一点慢,我们当然希望尽可能快。
  • 占用代码空间
  • 花时间编写代码并测试解除分配器
  • 违反了“没有代码执行得比'无代码'”格言。

HTH! FWIW,这是“当天回归”,当时内存非虚拟且极小,盒子速度慢得多,前两个是非常重要的考虑因素。

答案 2 :(得分:13)

我的感觉就像“WTF !!!”

这样看:

  • 您选择的编程语言不包含垃圾收集器,我们不允许问为什么。

  • 你基本上是说你懒得放心地释放记忆。

好吧,WTF了。懒惰不是一个很好的理由,至少在没有释放它的情况下玩弄记忆。

只是释放内存,这是一个不好的做法,场景可能会改变,然后可能有一百万个原因你可以需要释放内存而且不做的唯一原因是懒惰,不要养成坏习惯,并获得习惯于做正确的事情,这样你将来会倾向于做正确的事情!!

答案 3 :(得分:8)

Joel Coehoorn是对的:

  

不应该造成任何问题。

     

然而,这并不完全正常。   静态分析工具会抱怨   关于它。最重要的是,它构建   坏习惯。

我还想补充一点,在编写代码时考虑重新分配可能比批次更容易,而不是之后尝试改进它。所以我可能会让它释放内存;你不知道将来如何使用你的程序。

如果您想要一种非常简单的释放内存的方法,请查看the "pools" concept that Apache uses

答案 4 :(得分:8)

不解除内存不应该是问题,但这是一种不好的做法。

答案 5 :(得分:5)

嗯,我认为这是不可接受的。你自己已经提到了潜在的未来问题。不要以为他们一定很容易解决。

像“......因为我希望整个计算消耗更少......”这些都是着名的最后一句话。同样地,使用某些功能重新编写代码是他们所讨论和永远不会做的事情之一。

在短期内不释放内存可能听起来不错,但从长远来看可能会产生大量问题。就个人而言,我认为这不值得。

有两种策略。要么从一开始就构建GC设计。这是更多的工作,但它会得到回报。对于许多小对象,使用池分配器并跟踪内存池可能会付出代价。这样,您可以跟踪内存消耗,并简单地避免许多类似代码但没有分配池的问题。

或者您从一开始就在整个程序中使用智能指针。我实际上更喜欢这种方法,即使它使代码混乱。一种解决方案是严重依赖模板,在引用类型时会占用大量冗余。

看一下像WebKit这样的项目。他们的计算阶段类似于你的,因为他们为HTML构建解析树。他们在整个计划中使用智能指针。

最后:“这是一个风格问题......邋work的工作往往会形成习惯。” - David Eddings的 Castle of Wizardry 中的丝绸。

答案 6 :(得分:3)

引用计数智能指针,如boost和TR1中的shared_ptr,也可以帮助您以简单的方式管理内存。

缺点是必须包装使用这些对象的每个指针。

答案 7 :(得分:3)

如果程序的运行时间非常短,那应该不是问题。但是,懒得放弃你分配的内容而且忘记你分配的内容是两件完全不同的事情。如果你只是丢失了轨道,那就该问自己,你是否真的知道你的代码对计算机做了什么。

如果你只是匆忙或懒惰,你的程序的生命相对于它实际分配的数量很小(例如,如果运行30秒,分配每秒10 MB不小)..那么你应该没问题

关于在程序退出时释放已分配的内存集的唯一“高尚”论点...应该释放所有内容以防止valgrind抱怨泄漏,或者只是让操作系统执行此操作?这完全取决于操作系统,如果您的代码可能成为库而不是短期运行的可执行文件。

运行期间的泄漏通常很糟糕,除非你知道你的程序将在很短的时间内运行而不会导致其他程序远比你的程序更重要的操作系统涉及打滑肮脏的传呼。

答案 8 :(得分:3)

之前我已经完成了这项工作,但发现很久以后,我需要程序能够在没有单独命令的情况下处理多个输入,或者程序的内容非常有用,需要将它们转换为一个库例程,可以在另一个程序中多次调用,但不会被终止。回到过去并重新设计该程序比从一开始就使其无泄漏要困难得多。

所以,虽然你已经描述了这些要求在技术上是安全的,但我建议不要这样做,因为你的要求可能有一天会发生变化。

答案 9 :(得分:3)

  

将动态使用相当复杂的   分配数据结构。在   特别是,它不适合RAII   风格编程。

我几乎可以肯定这是懒惰编程的借口。你为什么不能使用RAII?是因为你不想跟踪你的分配,你没有指向它们的指针吗?如果是这样,你如何期望使用分配的内存 - 总是有一个指向它的指针,其中包含一些数据。

是不是因为你不知道什么时候应该被释放?将内存保留在RAII对象中,每个对象都被某些东西引用,并且当包含对象被释放时,它们都会互相释放 - 如果你想将它作为服务器运行一天,每次迭代都是特别重要的服务器有效运行一个“主”对象,该对象包含所有其他对象,因此您可以删除它并且所有内存都会消失。它还有助于防止您改装GC。

是因为你的所有内存都被分配并一直保持在使用中,并且只在最后被释放了吗?如果是这样,请参阅上文。

如果你真的,真的想不出一个你不能泄漏内存的设计,至少要有使用私有堆的礼仪。在你退出之前销毁那堆,你已经有了更好的设计,如果有点'hacky'。

有些情况下内存泄漏是可以的 - 静态变量,全局初始化数据,类似的东西。但这些通常不大。

答案 10 :(得分:2)

我没有亲自使用过这个,但是既然你从头开始,你可能会考虑Boehm-Demers-Weiser conservative garbage collector

答案 11 :(得分:2)

  

你对此有何看法?

有些O / Ses可能无法回收内存,但我想你并不打算在这些O / Ses上运行。

  

作为备份计划,如果我的项目需要以服务器或交互方式运行,我认为我总是可以将垃圾收集器重新编译为源代码。

相反,我认为您可以生成一个子进程来执行脏工作,从子进程获取输出,让子进程在此之后尽快死掉,然后期望O / S执行垃圾回收

答案 12 :(得分:1)

答案实际上取决于您的计划有多大以及需要展示的性能特征。如果您永远不会释放内存,那么您的进程的内存占用量将远远大于其他情况。取决于系统,这可能会导致大量分页,并降低系统或您系统上其他应用程序的性能。

除此之外,上面所说的每个人都是正确的。它可能不会在短期内造成伤害,但是你应该避免这种做法。你将永远无法再使用该代码。尝试在之后改装GC将是一场噩梦。只要考虑去每个地方你分配内存并试图改造它但不要破坏任何东西。

避免这样做的另一个原因是:声誉。如果您未能解除分配,维护代码的每个人都会诅咒您的姓名,而您在公司的代表也会受到影响。 “你能相信他是多么愚蠢吗?看看这段代码。”

答案 13 :(得分:1)

如果确定将内存释放到何处并非易事,我会担心数据结构操作的其他方面也可能无法完全理解。

答案 14 :(得分:0)

总的来说,我同意这是一种不好的做法。

对于单次拍摄的节目,它可以没问题,但它有点像你不做你正在做的事情。

你的问题有一个解决方案 - 使用自定义分配器,它从malloc预分配更大的块,然后,在计算阶段之后,而不是释放自定义分配器中的所有小块,只需释放更大的预分配块记忆然后,您无需跟踪解除分配所需的所有对象以及何时解除分配。一个编写编译器的人也在很多年前向我解释了这种方法,所以如果它适用于他,它也可能适合你。

答案 15 :(得分:0)

除了操作系统(内核和/或C / C ++库)可以选择在执行结束时不释放内存这一事实外,您的应用程序应该始终提供适当的释放分配内存作为一种良好做法。为什么?假设您决定扩展该应用程序或重用代码;如果您之前编写的代码在完成其工作后不必要地占用了内存,您很快就会遇到麻烦。这是内存泄漏的一个秘诀。

答案 16 :(得分:0)

尝试在方法中使用自动变量,以便它们从堆栈中自动释放。

不释放堆内存的唯一有用的原因是节省了free()方法中使用的微量计算能力。如果由于虚拟内存需求较大且物理内存资源较少而导致页面错误成为问题,您可能会失去任何优势。需要考虑的一些因素是:

如果要分配一些大块内存或许多小块。

是否需要将内存锁定在物理内存中。

对于Win32系统,包括内存空洞和填充在内,您是否绝对肯定所需的代码和内存将适合2GB。

答案 17 :(得分:0)

这通常是一个坏主意。您可能会遇到某些情况,程序会尝试消耗比可用内存更多的内存。此外,您还有可能无法启动该程序的多个副本。

如果您不关心上述问题,您仍然可以这样做。

答案 18 :(得分:0)

退出程序时,分配的内存为automatically returned到系统。所以你可能不会释放你分配的内存。

但是当您选择OSEmbedded systems等较大的程序时,解除分配是必要的,其中run foreverrecommended to deallocate&因此,小内存泄漏可能是恶意的。

因此,您分配的内存总是void inputStudent(struct Student **s)