在C语言中为什么需要释放内存?

7
我可能有所误解,但据我所知,操作系统在程序退出或崩溃后会清理内存。
如果是这样,那么在程序结束时进行内存释放有多大的用处?我知道,如果一个程序正在运行并且忽略了内存释放,那么内存可能会变得“满”,但是如果程序已经要结束了,并且操作系统会释放程序使用的所有内存,那么手动释放该内存的意义何在?

如果所有允许的内存都被使用了(当您不释放内存时),但现在您需要更多的内存怎么办?因此,您需要释放当前未使用的内存并使用它。 - user2734982
回复晚了,但这个问题是为了在程序结束时释放内存,因此不需要分配任何大量的新内存。 - Rik Schaaf
6个回答

4

清洁。

当然,您可以不费心进行清理,让系统来处理。然而,如果这样做,您基本上无法追踪程序中的内存泄漏,因为您无法运行它并查看结束时是否有任何未分配的内容。另一方面,如果您确保干净的关闭,您可以通过运行程序并查看结束时是否有任何未分配的内容来知道是否存在任何泄漏。由于对于任何运行一段时间的非微不足道的程序,内存泄漏都是要避免的事情,因此以这种清洁的方式进行操作会带来好处。

此外,这也是确保您的程序以正确条件关闭并释放任何外部资源(虽然大多数现代操作系统都会在这些天自动清除),因为您正在进行有序的关闭而不仅仅是强制关闭程序。


在复杂的、多线程应用程序中,代码清洁是非常重要的。那些试图“干净地”关闭这样的应用程序而没有任何重大原因的人,必须设计、编写和测试额外的、不必要的关机代码,这可能非常棘手且容易出错。用户代码无法可靠地终止运行在请求进程终止之前的另一个核心上的线程,并释放内存。只有操作系统具有跨处理器通信来执行这样的任务。如果可能的话,应该让操作系统自己完成这项工作。编写用户代码来关闭这样的应用程序是过早的优化。 - Martin James

4
引用自C语言中的内存释放问题
操作系统负责维护应用程序的资源,包括其内存。当应用程序终止时,操作系统将重新分配这些内存给其他应用程序。终止应用程序的内存状态是否损坏并不影响此过程。事实上,应用程序终止的原因之一可能是其内存已损坏。在异常程序终止的情况下,清理工作可能无法完成。
尽管如此,在程序正常终止时,有其他原因需要释放内存:
1. 高质量的程序员希望释放内存。即使应用程序正在终止,释放内存也始终是一个好习惯。
2. 如果使用了检测内存泄漏或类似问题的工具,则释放内存将清除此类工具的输出。
3. 在一些较简单的操作系统中,操作系统可能不会自动回收内存,而可能是程序在终止前负责回收内存。
4. 此外,应用程序的后续版本可能会添加代码。如果以前的内存没有被释放,可能会出现问题。

2
虽然你的回答非常清晰,但你忽略了释放内存对程序终止的负面影响。以下是同一网页中的一句话:“另一方面,在程序终止之前确保所有内存都被释放:
  • 可能会带来更多麻烦;
  • 对于复杂结构的解除分配可能会耗费时间和复杂度;
  • 可以增加应用程序的大小;
  • 导致运行时间更长;
  • 增加了更多编程错误的机会。
是否在程序终止之前应该释放内存取决于应用程序。”
- Rik Schaaf
并非所有操作系统在应用程序终止后都会释放内存。我曾经在一些实时系统上工作过,它们不会这样做。 - user3344003

1

不同的视角:

在程序结束时,通常没有特定的实际原因需要清理内存。但是对于不能放在单个页面上的非平凡程序,通常不会这样设计!程序的各个部分通常需要被设计成在程序执行的任何时间点都能够良好运行,而且通常不需要了解程序的其他部分。它们不能永久地分配和占用内存,因为一般来说,它们不知道自己会被调用多少次,后面会有多少代码跟随,或者持续多长时间。毕竟,许多最终用户应用程序都被设计为运行潜在无限的“主循环”。

因此,一个完全清理自己的程序并不是一个目标,而是从根本上正确设计整个程序的较小后果之一(强迫症者的奖励!)。如果在结束时还有资源剩余,它也可能作为某个设计过程阶段未按计划进行的警告标志。


啊,是的,我没有考虑到这一点,因为我对于复杂或长时间运行的程序使用垃圾回收语言。我主要使用C语言来处理IO,例如计算或建模等。在这些情况下,程序在一定的时间内结束,这与用户输入无关,除了命令行参数和输入文件。除了一次之外,我从未接近现代计算机的内存限制,而这些程序在几秒钟到最多几分钟内终止。 - Rik Schaaf

0

你不能总是依赖系统,尽管大多数现代系统都这样做。据我所知,Windows 95没有这样做,因此可能还有一些野生的嵌入式系统也不会在进程结束后清理资源。

除此之外,这是一个好习惯。有时候你会将一些东西从main函数中重构到某些模块中并尝试重用它们。记得释放资源是很好的习惯。


我认为今天为Win 95编程是不合理的。所有现代操作系统在进程退出后会回收分配给该进程的虚拟内存。 - Michael Aaron Safyan
2
哦,你会惊讶于ATM使用的东西。而且那只是一个例子。“所有现代操作系统”-如果我找到一个不行的,你会给我钱吗?不要带着如此强烈的量化词去理所当然地看待事物,这比为win95编程更加危险和不合理。 - luk32
好的,考虑到我们正在谈论“C”语言,它被用于各种嵌入式和后向设备,我想你说得有道理。尽管“现代”是一个相当主观的标签,但我认为我所说的确实是真的。ATM(需要安全性)运行在如此过时的技术上是相当不合理的;我认为升级而不是维护那样的代码是相当合理的。 - Michael Aaron Safyan
微软将因为定制支持WinXP而赚取大量资金,因为绝大多数ATM都在其上运行。这是一个商业决策,虽然我同意也许Win95正在走向极端,但现在的WinXP听起来并不好,这是一个严重的问题,不仅仅是所有/除了一个挑剔的问题。 - luk32

0

没错。如果有一些对象将在整个应用程序的生命周期内存在,那么在启动时分配它一次并永远不释放/删除该对象是合理的。然而,如果您将某些东西分配为计算的一部分,并且没有必要保留该对象的整个生命周期,则重要的是在不再需要该对象时释放它;否则,随着对象在程序的生命周期中泄漏,您的程序将慢慢耗尽可用内存。

需要注意的是,即使您释放了内存,也总有可能在您有机会释放内存之前强制终止程序(例如通过信号)。因此,这是不必过于担心的一个原因。话虽如此,为了保持一致性和良好习惯,无论是常规分配/释放还是长期对象的分配/释放,我通常更喜欢像常规对象一样释放/清理长期对象。话虽如此,您应该平衡清理的愿望与快速关闭以及在强制关闭事件发生时能够生成正确的核心转储/日志的能力。例如,花时间释放大型长期数据结构可能会影响编写核心转储的时间,在这种情况下,编写核心转储可能更好。


0
一般来说,如果在不再需要时不释放内存,会耗尽系统的内存资源,这就是所谓的内存泄漏。
长时间运行的程序最容易出现这种情况。随着运行和分配更多的内存(例如调用malloc),程序消耗的内存资源也越来越多。如果不将它们返回给系统,那么当调用“malloc”时,操作系统就可能开始没有足够的内存可供其应用程序使用了。
某些操作系统和编程语言具有可以缓解或防止此类问题发生的功能。
例如,Java不允许直接调用malloc和free。相反,当您创建对象时,Java运行时会为它们分配内存。当您完成变量(即当它们超出范围时)时,它们被标记为“垃圾回收”。通常,周期性地运行“垃圾回收”任务或函数,并在所有不再使用的变量关联的内存上调用free(即“清理垃圾”)。
一些操作系统还支持对进程和/或线程的运行时限制,以防止它们消耗“所有”系统资源。如果达到任何这些限制,操作系统可以停止程序的执行。
希望这有所帮助, - J.

好的,但是假设你有一个需要进行复杂计算的应用程序。它运行大约一分钟,使用有限的内存并释放临时分配的变量,但是将长期存在的数据留给操作系统进行处理。除了代码重用问题之外,在现代Windows/Linux操作系统上这样做是否有任何问题? - Rik Schaaf
不,没有任何阻止您采取这种方法的东西。虽然这被认为是一种不好的做法,但它确实可以工作。现代操作系统(Linux、Windows NT及其后续版本)都足够智能,在进程退出后恢复所有进程资源。 - jrjbertram
如果你谈论时间效率,哪种方法是最好的?在这方面,Linux和Windows有区别吗? - Rik Schaaf

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