如果程序已经退出,为什么还需要免费资源?

27

许多库,例如SDL等,在其教程中调用方法来在退出程序之前释放资源,但据我所知,大多数操作系统在退出进程时会释放所有内存,那么如果应用程序将要退出,为什么我还需要费心去释放它们呢?

许多库的教程中包括在退出程序之前释放资源的方法调用,主要出于以下原因:虽然大多数操作系统在进程终止时会回收所有内存,但是对于某些特殊的资源(如打开的文件、网络连接等),这些资源必须在程序终止之前手动释放,否则可能会导致一些问题,比如数据损坏、泄漏等。因此,在编写程序时,建议始终按照库的教程进行资源释放操作,即使您认为某些资源不需要手动释放。


也许,只是为了保持一致?一个好习惯? - Nawaz
虽然这个问题有一定的价值,但我认为它不适合在SO上讨论,因为如果没有特定的使用情境,这只会导致一场宗教战争。 - John Dibling
18个回答

27

内存和资源并不是同一回事。

内存会被自动释放。

资源可能会自动释放,也可能不会。


3
现代操作系统中哪些内容不会自动释放?能否提供示例? - user216441
我猜测位图句柄会自动释放,而扫描仪的句柄可能不会,这取决于设备驱动程序。 - Steve Wellens
4
共享内存在进程退出时通常不会被释放。 - John Dibling

24
即使您的操作系统(并非所有操作系统都是这样)在退出时会释放内存,但仍有一些原因:
  • 这是良好的习惯
  • 它增加了对称性,使代码看起来更好
  • 操作系统不会自动释放某些资源,例如设备(传感器、扫描仪等)
  • 如果有人拿取此代码并将其放在仅在程序的一小部分运行时间中使用库的程序中,则当不需要时资源将被释放。
  • 如果您正在寻找糟糕的内存泄漏,您的调试器将无法找到这些不重要的泄漏。

8

分配给程序的资源是否会被回收取决于操作系统。请注意,某些嵌入式系统不会释放资源。

大多数操作系统会回收和释放已分配的资源,但依赖操作系统的行为是不好的实践方法,因此在退出程序之前,您应该释放所有已获取的资源。


4
依赖操作系统行为是个不好的实践,因为如果不依赖操作系统行为,就无法读取或写入数据。例如。 - James Kanze
@JamesKanze:为确保您的程序在各个平台上都具有可移植性。 - Alok Save
3
但是,你也不会进行任何输出或输入。与依靠操作系统回收内存相比,输出和输入可能不太具有可移植性。实际上,如果你在托管环境中,操作系统将会回收内存。但在独立的环境下,你不能依赖它。但是在独立的环境下,你也不能保证iostream存在。 - James Kanze

5
总的来说,我同意其他人所说的:如果你在小事上不养成好习惯,你也会在大事上失败。然而,你的问题让我想起了一个仅崩溃软件的老概念。
虽然这个概念比你原来的问题(它不仅涉及操作系统资源,还涉及你自己的(打开的文件等)更深入一点,但你可能仍然对它感兴趣。
基本思想是,如果软件在崩溃时不应该破坏用户数据等(考虑数据库/ tx 日志等),为什么你甚至要设计/编程一个干净的退出路径。如果你需要重新启动、重新运行它,你可以“让它崩溃”。
嗯,我想一个人可以争论这个美德整整一天,但它仍然很有趣。

4
我想首先要提到的是并非所有资源都相同。
在大多数操作系统中,以下结构在应用程序关闭时不会自动清除:
- 共享内存池 - 命名的Win32互斥体/信号量/事件等对象 - 某些类型的套接字连接 - 专有硬件设备驱动程序数据结构(晦涩)
我相信我忘记了一些。
在小型项目中,您可能很容易知道您的应用程序是否使用了这些类型的对象并为其进行控制。然而,在较大的应用程序中,您很容易达到这样一个点:您有一些深度嵌入式(第三方?)子系统,它确实分配了一个或多个这些特殊结构,如果您的应用程序像漏斗一样泄漏,您可能会遇到麻烦。
这实际上是一种工程纪律,即您的应用程序应该在退出时清理自己。您现在可能不需要它,但随着应用程序越来越大,您可能会感激它。

4

把自己留下的东西整理好是个好主意。

首先,释放资源将以控制的方式整理文件描述符/网络连接/共享内存等资源。

其次,如果你正在使用像purity这样的工具,可以确保所有内存都被考虑在内,从而更好地判断是否出现了内存泄漏。


3
首先:并非所有资源在进程结束时都被操作系统释放,例如:
  1. 文件 - 有时您可能需要删除已打开的文件。
  2. 命名资源:命名互斥体、共享内存等等。
  3. 更复杂的应用程序级状态设置、统计数据等等。
因此,一旦您以相同的方式管理所有资源,就是正确的做法。

2
至少在Windows中,所有对内核对象的句柄(即文件、命名互斥量等)都会在进程关闭时关闭。 - Seva Alekseyev
2
至少在Linux中,当进程从进程表中删除时,所有文件描述符(即文件、命名互斥量等)都会关闭。 - deft_code
我所说的东西,比如命名互斥量 - 它们不会自动销毁或SYSV共享内存和IPC等等,它是持久的。mq_队列是持久的,还有更多。当然,可能会有应用程序临时文件,例如sqlite3日志等等。因此,有许多资源并非全部由操作系统清理。 - Artyom

3
您是正确的,大多数现代操作系统会在应用程序退出时为您释放内存、文件句柄等资源。因此,如果应用程序可用的资源是无限的,我完全同意您的看法,并不需要释放任何资源。
事实上,资源并不是无限的,恰恰相反,它们是有限的,这意味着您所占用的资源是其他正在运行的应用程序无法获得的。在许多情况下,您只需要在应用程序的某个部分使用资源,而不是在整个应用程序的生命周期中使用资源,所以您需要与系统的其余部分友好相处,并且只取您需要的资源。
在嵌入式设备中,不释放资源的做法非常普遍,因为对于这些设备,应用程序是唯一运行的东西,甚至没有退出的选项,唯一的出路就是关闭设备电源。我正在使用这种系统进行工作,虽然嵌入式设备没有因未释放资源而出现问题,但我们工程师却有各种问题:
  • 当在常规PC上测试嵌入式应用程序时,我们被迫将模拟设备建模为启动和结束进程。如果资源被适当地释放,我们可以使单个进程在同一运行中运行多个测试,包括启动和停止模拟设备的测试。
  • 在某个时刻,我们必须将嵌入式代码的一部分作为Windows/Linux的动态链接库发布,以执行真实设备子集的函数,但没有实际设备。由于资源问题,用户不能将此DLL多次加载到其应用程序中,因为每次这样做都会占用相当大的内存并永远不会释放。我们已将其记录为限制,并要求用户将库链接到应用程序中,而不是动态加载它。不幸的是,在嵌入式设备开发了10多年后,定位和修复所有这些资源分配将非常复杂,因此我们继续推迟处理,产品效果也不尽如人意。
  • 当我们使用静态和动态代码分析工具来查找真正的缺陷时,我们会得到大量的虚警,以至于我们不得不开发工具来过滤这些虚警,以免冒失错过真正的缺陷。
我的建议是您编写代码时,最好不要指望操作系统帮助您释放资源,因为这样能让您在未来改进软件时拥有更多选择。

3

我认为其中一个原因是:

假设您在应用程序退出时在开发环境的输出窗口中收到内存泄漏信息。如果您没有以正确的方式进行“清理”,那么您将难以检测出真正的泄漏,而且还会有很多来自“不去理会”的泄漏。


3

今天几乎所有主流操作系统的确在程序终止时释放了程序已分配的所有(或大多数)资源,这是大部分正确的。然而,首先并非所有资源都是如此(例如,在我的Mac上,如果程序没有正常关闭,打开的套接字会保持一段时间),其次我认为不是所有操作系统都是如此。

从历史上看,操作系统根本不关心程序终止时的资源清理(特别是一些旧的16位操作系统),所以清理所有资源已成为良好的编程实践,一个不清理自己代码的程序员通常被认为是一个糟糕的程序员。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接