27

许多库(如 SDL 等)在他们的教程中都有方法调用在退出程序之前释放资源,但据我所知,大多数操作系统在退出时会从进程中释放所有内存,为什么我需要费心去释放如果应用程序无论如何都要退出?

4

18 回答 18

26

内存和资源不是一回事。

内存会自动释放。

资源可能会或可能不会自动释放。

于 2011-11-25T15:40:36.513 回答
23

即使您的操作系统(并非所有人都这样做)在退出时释放内存,也有一些原因:

  • 这是很好的方式
  • 它增加了对称性,因此代码看起来更好
  • 操作系统不会在退出时自动释放某些资源,例如设备(传感器、扫描仪......)
  • 如果有人获取此代码并将其放置在仅在其运行时的一小部分使用库的程序中,则资源在不需要时将是免费的。
  • 如果您正在寻找严重的内存泄漏,您的调试器不会找到这些不重要的。
于 2011-11-25T15:45:49.343 回答
8

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

大多数操作系统确实回收并释放分配的资源,但依赖操作系统的行为来实现这一点是不好的做法,因此您应该在退出程序之前释放所有获取的资源。

于 2011-11-25T15:40:01.897 回答
5

总的来说,我同意其他人所说的:如果你不在小事上养成好习惯,你也会在大事上失败。但是,您的问题(一个旧的)响起,关于仅崩溃的软件。

尽管该概念比您最初的问题“稍微”扩展了一些(它不仅涉及操作系统资源,还涉及您自己的(打开的文件等),但您可能仍然对它感兴趣。

基本思想是,如果软件在崩溃时不应该破坏用户数据等(想想数据库/tx 日志等),为什么还要设计/编写干净的退出路径。如果需要重启,重新运行,还不如“让它崩溃”。

好吧,我想人们可以整天争论它的优点,但这仍然很有趣。

于 2011-11-25T15:44:43.713 回答
4

自己整理一下是个好主意。

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

其次,如果您使用类似的东西,purity您可以确保考虑到所有内存 - 从而更好地了解没有发生内存泄漏。

于 2011-11-25T15:44:57.110 回答
4

我想首先应该提到的是并非所有资源都是相同的。

这些结构(在大多数操作系统中)都不会在应用程序关闭时自动清理:

  • 共享内存池
  • 命名为 Win32 Mutex/Semaphore/Event/etc。对象
  • 某些类型的套接字连接
  • 专有硬件设备驱动程序数据结构(晦涩)

...我确定我忘记了一些。

在小范围内,可能很容易知道您的应用程序是否使用任何这些类型的对象并对其进行控制。但是,在较大的应用程序中,不难达到一个深度嵌入的(第 3 方?)子系统分配一个或多个这些特殊结构的地步,如果您的应用程序的其余部分像筛子一样泄漏,你可能有麻烦了。

这实际上是一个工程学科的问题,它说您的应用程序应该在退出时自行清理。您现在可能不需要它,但随着您的应用程序变得越来越大,您可能会喜欢它。

于 2011-12-02T04:15:50.130 回答
3

我看到的一个原因是:

假设您在应用程序退出时在开发环境的输出窗口中转储了内存泄漏。如果您没有以适当的方式“清理”,您将无法从“不打扰它”的所有泄漏中检测到真正的泄漏

于 2011-11-25T15:39:58.233 回答
3

好吧,今天几乎所有主流操作系统确实释放了程序在终止时分配的所有(或大部分)资源,这几乎是真的。然而,这首先不适用于所有资源(例如,在我的 Mac 上,打开的套接字在程序终止时未正确关闭时会保持打开一段时间),其次我相信并非所有操作系统都如此。

从历史上看,操作系统根本不会打扰(尤其是一些较旧的 16 位操作系统),因此在编程终止时清理所有资源已经成为并且仍然是良好的编程实践,程序员不清理他的东西通常被认为是一个糟糕的程序员。

于 2011-11-25T15:43:31.533 回答
3

首先:当进程结束时,操作系统不会释放所有资源,例如:

  1. 文件 - 有时您可能会删除已打开的文件。
  2. 命名资源:命名互斥体、共享内存等。
  3. 更复杂的应用程序级别状态设置、统计信息等等。

因此,一旦您以相同的方式管理所有资源,您就是在做正确的事情。

于 2011-12-01T14:36:44.377 回答
3

您是对的,大多数现代操作系统会在应用程序退出时为您释放内存、文件句柄等。因此,如果应用程序可用的资源是无限的,我完全同意您的看法,并且不会费心释放任何资源。

事实是,资源不是无限的,实际上恰恰相反,所以你得到的任何东西都是系统上运行的另一个应用程序所不能拥有的。在许多情况下,您需要的资源不是贯穿应用程序的整个生命周期,而只是其中的一部分,因此您希望与系统的其余部分配合得很好,并且只在需要时获取所需的资源。

不释放资源的做法在嵌入式设备中很常见,因为对于这些设备,应用程序是唯一运行的东西,它甚至无法退出,唯一的出路就是关闭设备。我使用这样一个系统,虽然嵌入式设备不会因为不发布东西而出现问题,但我们工程师会因为以下几个原因而受苦:

  • 在普通 PC 上测试嵌入式应用程序时,我们被迫将模拟设备建模为一个开始和结束的过程。如果资源被正确释放,我们可以让一个进程在同一次运行中运行多个测试,包括启动和停止模拟设备的测试。
  • 在某些时候,我们不得不处理一个项目,该项目要求我们获取部分嵌入式代码并将其发布为 Windows/Linux 的动态链接库,该库执行真实设备的部分功能,但没有实际设备。由于资源问题,用户不能在他们的应用程序中多次加载和卸载此 DLL,因为每次他们这样做时都会占用相当大的内存块并且永远不会释放回来。我们已将其记录为限制,我们要求用户将库链接到应用程序,而不是动态加载它。不幸的是,在这个嵌入式设备已经开发了 10 多年之后,定位和修复所有这些资源分配将非常复杂,所以我们一直推迟它,而是有一个次优的产品。
  • 当我们使用静态和动态代码分析工具来定位真正的缺陷时,我们会得到大量的误报,以至于我们不得不开发工具来过滤掉这些缺陷,以免在所有噪音中遗漏真正的缺陷。

我的建议是,您编写代码时就像操作系统不会帮助您一样,因为这将为您提供未来改进软件的最多选择。

于 2011-12-02T02:21:06.380 回答
2

这些都是很好的礼仪。

而且你永远不知道你是否想把你的程序变成在未来不断重复运行的东西。

也就是说,这不是强制性的,如果您知道自己在做什么,则可以一如既往地违反规则。

于 2011-11-25T15:39:04.000 回答
2

操作系统试图释放进程关闭后仍保留的所有资源,作为保持系统运行的最后努力。应用程序应该自行清理,但操作系统的自动清理旨在阻止编写不当的程序因内存泄漏、保留文件等导致整个系统瘫痪。所以你真的不应该依赖它作为你的应用程序的默认模式被关闭!理想情况下,操作系统将永远不必在进程关闭后进行清理,因为所有程序都应该编写得很好,以便自行清理。然而,在实践中,一些软件有错误或者只是写得不好,在这些懒惰的程序之后,操作系统清理它是一个有用的功能。

此外,操作系统无论如何都不会清理一些资源。如果您将文件写入磁盘并打算在关闭时将其删除,则操作系统不会自动删除该文件(如果它是用户的文档怎么办?)。但是,如果您不自己清理它,您的程序就会永久“泄漏”磁盘空间。对于文件以外的其他类型的资源,还有许多其他示例。

因此,不要编写假设操作系统会清理的糟糕软件:它可能不会 100% 做到这一点,而且这种机制仅适用于糟糕的软件。不如写好软件!

于 2011-12-04T15:41:17.007 回答
1

一旦您尝试使用 Valgrind 或其他工具查找内存泄漏,即使对于生命周期与应用程序的生命周期相对应的对象,释放内存的感觉也会立即显而易见,因为您的输出将充满关于这些对象的报告。毕竟,泄漏仍然是泄漏。

于 2011-12-04T19:39:41.777 回答
0

应用程序退出时不需要释放内存。操作系统负责回收内存。正如其他人所提到的,打印机、文件等资源需要释放它们的锁以允许其他程序访问它们。

假设您的代码没有释放任何内存(即使它运行时),并且当您的代码/项目大小增加时,它会占用您所有的系统内存并且维护变得难以修复它们。因此,对于所有未来的目的,释放内存是一个很好的做法。

于 2011-12-02T12:53:38.520 回答
0

如您所知,根据操作系统,内存通常(希望是!)在进程退出时自动释放。

然而,许多库,如 SDL,要求操作系统分配系统资源,这些资源不会及时释放(甚至可能直到关闭),除非应用程序明确释放

除了对操作系统友好并为其清理之外,释放您分配的任何内存对于运行时间未知的任何应用程序都很重要,因为该内存占用了其他应用程序可能需要的空间。

自己打扫卫生也是一个好习惯。:)

于 2011-12-03T09:17:03.060 回答
0

正如其他答案所指出的,资源和内存之间存在差异。我只能在 Win32 api 的上下文中发言,但我确信类似的概念适用于 SDL 等库。有些库可能会提供资源的自动释放,有些可能不会。无论如何,释放资源始终是一种好习惯。设备特定资源是如果不释放可能会导致问题的资源的一个示例。您可能需要查看库的文档以获取有关资源管理的详细信息。

于 2011-12-04T04:48:16.363 回答
0

我知道我迟到了,但请释放你所有的内存和资源,如果没有其他原因,只是因为当你最终得到真正的内存泄漏时,比如在循环中,那么我最不需要的就是你的垃圾像 valgrind 一样弄乱我的内存分析器输出。

其次,清理内存不是问题,使用智能指针可以为您完成所有工作,几乎没有开销。

最后,如果它是一个库,这更加不可原谅,我不在乎它是否不是连续泄漏(即 1 个垃圾 - 例如:创建一个单例),一个库不应该在 freestore 上留下数据。

于 2011-12-05T15:57:18.443 回答
-1

每当任何新进程启动时,都会为其分配一些内存。内存可以有四种类型:

 1.Heap
 2.Local
 3.Virtual
 4.Global

Local 通常用于 main() 变量的地址,因为这些主要变量会经常使用。Global 保存全局变量的记录。堆内存分配给程序或进程(分配页面),它具有程序数据和功能的信息。

操作系统使用指针的概念实际上会发生什么。并且每当在程序中一个指针开始指向其他内存(由于某些代码错误)并停止指向前一个内存位置时,最后一个内存空间仍在堆内存中使用。但是这个内存空间是没有用的。当任何程序退出时,它会根据其变量和函数位置释放内存。但正如我所说,未指向的内存仍然有数据,但没有人指向它,所以程序无法释放它。

为了释放未使用的内存位置,我们使用 free()。因为malloc、realloc、calloc、free都是堆内存的函数。当我们调用 free 时,它​​会删除为程序分配的页面,并且还会释放未使用的内存。

  In simple words,

分配给您的程序的 50-100 个内存位置。a 和 b(程序中的变量)指向 60 和 70。由于一些代码错误,b 开始指向 60。所以现在 a 和 b 都指向 60。现在没有人指向 70。当程序开始退出时,它将获取a的内存位置并释放它。然后它将获取b的内存位置并释放它。但是程序永远不会知道70的位置,因为没有人指向它。所以它不会释放70的内存。

而当您调用 free() 时,它会直接释放整个页面,并且将释放整个 50-100 个内存位置。现在,未指向和指向的内存位置都可以免费使用。

现在有一天,语言有垃圾收集器来完成 free() 的功能。但是,如果我们谈论操作系统,那么它们必须自己做,所以在库中总是使用免费的。这也是编写代码的最佳方式。

于 2011-12-04T16:50:38.067 回答