【问题标题】:There is no point in freeing blocks at end of program? [duplicate]在程序结束时释放块没有意义吗? [复制]
【发布时间】:2011-09-14 20:59:10
【问题描述】:

可能重复:
Is freeing allocated memory needed when exiting a program in C

我正在阅读"Freeing Memory Allocated with malloc"的页面并看到这句话:

在程序结束时释放块是没有意义的,因为当进程终止时,程序的所有空间都会归还给系统。

我知道作者想说什么,但句子不应该是:

在程序结束时释放块是没有意义的,因为当进程终止时,程序的所有空间都归还给系统,尽管你仍然应该确保你的程序释放了所有的 malloc'ed退出前的内存

或者在进程终止之前不释放内存是常见的做法吗?

【问题讨论】:

  • 如果无论如何都会释放所有内存,为什么要确保在程序存在之前释放所有内存?对我来说,这似乎是不必要的。不过,如果有任何理由应该知道你应该这样做会很有趣!
  • @Blagovest:啊!类似的问题。在我的辩护中,我确实进行了搜索,但可能错过了这一点。我也投票赞成结束。
  • @Ancide:代码重用是原因之一。如果你的main 函数,或者它调用的东西来做繁重的工作,“泄漏”内存,那么你就不能将该代码用作其他东西的一部分。也许您不想这样做,这没关系,但这确实意味着您必须以某种方式区分适合一般用途的代码和只应在调用返回后不久退出的进程中调用的代码。

标签: c malloc free


【解决方案1】:

我为此付出了很多努力,但我的立场是,在程序退出之前努力释放内存应该被认为是有害的。一方面,它需要额外的代码来维护和调试——但可能不会太多,所以这只是一个小问题。更大的问题是实际效果。

假设您有一个长期存在的程序,该程序分配了复杂/深度的数据结构 - 作为一个很好的例子,想想网络浏览器。很可能这些数据中的大部分已经有一段时间没有使用过了,而且还被交换到了磁盘上。如果您只是exit,则磁盘上换出的数据将被简单地标记为未使用并且永远不会再被触及。但是,如果您遍历程序的所有数据结构以释放它们,您将接触到每个换出的页面,从而导致:

  • 磁盘访问以读取换出的数据
  • 从内存中逐出其他程序的实际重要数据
  • 以及相应的磁盘访问以换出属于其他程序的所述数据。

所有这些浪费:

  • 用户的时间
  • 在 HDD 上磨损(或者更糟的是,在 SSD/闪存上)

如果您使用足够臃肿的桌面应用程序(Firefox、OpenOffice、GIMP 等或 Windows 等价物)使系统超载以使其交换,然后尝试关闭其中一个,则很容易观察到此行为。您将花费几秒钟(甚至可能是 ~30 秒,因为交换已经够糟糕了)等待它退出。如果程序刚刚直接调用exit(在检查未保存的文档等之后)它会立即关闭。

【讨论】:

  • 这是一个非常有趣的答案,我必须选择这个作为正确的答案(对不起!)。我希望(像往常一样)我可以选择多个答案。
  • 在一天结束时我正在检查 SO 的事实意味着我几乎必须给出这个 +1 - 关闭操作的性能非常值得考虑。
  • 顺便说一句,多线程程序中的另一个考虑因素是在程序关闭时正确释放所有内存可能需要非平凡的同步。如果您弄错了并释放了一些内存,稍后您的清理例程的另一部分会尝试访问这些内存,您将调用未定义的行为。充其量程序会崩溃,但更糟糕的事情可能会发生,无论哪种方式,这都是糟糕的用户体验。因此,简单地退出可以为您节省大量难以调试的程序逻辑。
  • 当程序的大部分内存分配不是由主程序而是由它调用的库分配时,您认为这有多难?可能有要刷新的缓冲区、要通知的网络合作伙伴等等,因此您不能简单地调用exit,而必须调用这些库的清理例程。这些库中的大多数可能只是有一些例行程序以例行方式关闭其内容,包括刷新缓冲区和释放内存(以及其他结束任务),而不是说“我们正在退出,只是结束基本任务”的例程东西。”那么能获得多少收益呢?
  • @EricPostpischil:你真的不需要为它们调用清理例程,除非它们处理需要保存的状态。您只需 exit 并丢弃他们的状态。图书馆重新分配/关闭/等。函数在此处的处理方式与free 完全相同:如果您想在继续运行时恢复它们正在使用的资源,您需要做的事情,而不是您在退出时武断地做的事情。
【解决方案2】:

(这是一个非常主观的答案,所以请随心所欲。)

我认为这是一种很好的做法,以防你最终添加到进程中,在这种情况下你可能想释放内存。

我认为只在需要时保留动态内存然后释放它总是好的。我通常喜欢在写完malloc 之后立即在我的代码中写free,然后在其间添加我需要的任何代码。

【讨论】:

  • 对于短期分配来说,这绝对是正确的——你应该在完成它们后立即释放它们。但是,如果您知道某些内存保存着在程序终止之前您不会“完成”的数据,那么释放它就没有任何意义。
  • 加1表示括号。 :-)
【解决方案3】:

我个人的偏好是在程序结束时释放内存 - 代码没有任何用处,但如果执行不正确仍然可能产生/导致错误。

同时,保留分配的内存将触发来自几乎所有自动泄漏检测器的报告,因此,如果您正在使用(或曾经可能)使用一个(或曾经可能),最好释放内存以防止真正的泄漏丢失/忽略.鉴于它们今天的流行,很难(如果可能的话)确定你也永远不会使用这样的东西。

【讨论】:

    【解决方案4】:

    在不释放内存的情况下退出程序是很常见的做法。

    这是否是最佳实践当然有待讨论 - 一个程序中的 main() 经常演变为另一个更大程序中的函数调用,当这种情况发生时,您希望您的内存(取消)分配直接。再说一次,对于小程序来说,这可能只是一个麻烦和多余的工作。

    【讨论】:

      【解决方案5】:

      在程序结束时释放内存的最佳理由是发现泄漏。至少有一些分析器,比如 purify,会声称当你在程序结束前没有释放时,一切都被泄露了。现在,您知道从内存释放到操作系统的意义上说,这并不重要,但它使您更难判断是否存在您确实打算释放但意外没有释放的东西。这对于长时间运行的进程很重要,例如服务器进程、守护进程等,内存泄漏可能会导致重大问题。对于完成一项工作然后立即退出的简单程序,我真的认为如果你明确地释放它并不重要。

      【讨论】:

      • 仍然可以实现这一目标的一种方法是在调试版本中启用“free-everything-at-exit”代码。
      • @R..:对我来说听起来很合理。将“退出时不释放所有内容”视为一种优化,因此编写代码,然后根据可测量的性能决定是否实际调用它。不过,就我个人而言,我希望在调试版本中以两种方式进行,以便“非免费”情况下的任何错误仍然在调试条件下得到执行。然而,not 运行代码听起来不太可能是一个错误,但我们可以想象某些组件会在清理时尝试刷新应用级缓冲区。好的,所以刷新可能会失败,但也许我们仍然想尝试一下。
      【解决方案6】:

      有些东西我非常努力明确地释放。例如,线程间通信对象池。我希望操作系统在释放进程内存之前先释放这些,因为它总是会停止我所有的线程(那些可能仍在写入对象的线程)。

      如果我不这样做,我会遇到试图终止卡在阻塞调用或运行循环中的线程的所有问题。不用担心所有的麻烦:)

      Rgds, 马丁

      【讨论】:

      • +1 不错的角度,我没有考虑过 - 在多线程应用程序中,同步终止可能非常困难,而且它是潜在的主要错误。
      • 操作系统在终止线程方面比我好得多,所以我更喜欢让它的设计
      猜你喜欢
      • 2016-08-15
      • 1970-01-01
      • 2012-01-25
      • 2018-07-03
      • 2012-10-04
      • 1970-01-01
      • 2010-10-26
      • 1970-01-01
      • 2023-03-15
      相关资源
      最近更新 更多