退出C应用程序时,已分配内存的内存是否自动释放?


92

假设我有以下C代码:

int main () {
  int *p = malloc(10 * sizeof *p);
  *p = 42;
  return 0;  //Exiting without freeing the allocated memory
}

当我编译并执行该C程序时,即在内存中分配了一些空间后,我退出应用程序且过程终止后,分配的内存是否仍会分配(即基本占用空间)?


9
这是清理内存的“好方法”,不是因为您可能在没有受保护的内存的操作系统上运行(这是下面的主要建议),而是因为它增加了您发现内存泄漏并保持的可能性。您的代码精益求精...
Matt Joiner 2010年

Answers:


111

这取决于操作系统。当程序结束时,大多数现代(以及所有主要)操作系统将释放程序未释放的内存。

依靠这种做法是不好的做法,最好将其明确释放。问题不仅仅在于您的代码看起来不好。您可能会决定将小程序集成到一个较大的,长期运行的程序中。然后过了一会儿,您必须花费数小时来跟踪内存泄漏。
依靠操作系统的功能还使代码的可移植性降低。


16
我曾经在嵌入式平台上遇到过win98,根据这种经验,我可以说程序关闭时它不会释放内存。
圣哈辛托

8
@Ken这是一个例子。同样,YAGNI和草率编码之间也有一条界限。不释放资源会越过它。YAGNI原则还应应用于功能,而不是使程序正常工作的代码。(并且不释放内存是一个错误)。
Yacoby

5
+1:最重要的要考虑的是,内存管理就如Yacoby所正确指出的那样:“操作系统的功能”。除非我没有记错,否则编程语言不会定义程序执行之前或之后发生的事情。
D.Shawley'2

9
手动释放内存会花费更多时间,更多代码,并引入可能的错误(告诉我您从未见过释放代码中的错误!)。故意遗漏某些情况对于您的特定用例而言并非“草率”。除非或直到您要在某个古老的/微小的系统上运行它,否则该系统在进程终止后无法释放页面,或者将其集成到更大的程序(YAGNI)中,对我来说似乎是净亏损。我知道考虑不自己清理它会伤害程序员的自我,但是实际上以哪种实用方式更好呢?
肯(Ken)

6
提议在SO上出现内存泄漏的任何人都应剥夺所有声誉和徽章
2012年

53

通常,现代通用操作系统会在终止进程后进行清理。这是必需的,因为替代方法是使系统随着时间的流逝而丢失资源,并且由于程序编写不当或仅具有很少发生的会泄漏资源的错误而导致程序需要重新启动。

出于各种原因,无论如何都要让程序明确释放其资源可能是一个好习惯,例如:

  • 如果您有其他资源在退出时不会被操作系统清除,例如临时文件或对外部资源状态的任何更改,那么您将需要代码来处理退出时的所有这些事情,通常与释放内存巧妙地结合在一起。
  • 如果您的程序开始具有更长的生存期,那么您将不希望释放内存的唯一方法是退出。例如,您可能希望将程序转换为服务器(守护程序),该服务器在处理针对单个工作单元的许多请求时保持运行,或者您的程序可能成为较大程序的一小部分。

但是,以下是跳过释放内存的原因:有效关机。例如,假设您的应用程序在内存中包含大缓存。如果退出时,它将遍历整个缓存结构并一次将其释放一次,这将无济于事,并浪费资源。尤其要考虑以下情况:包含高速缓存的内存页已被操作系统交换到磁盘上;通过遍历结构并释放它,您将所有这些页面一次全部带回到内存中,浪费大量时间和精力,没有任何实际好处,甚至可能导致系统上的其他程序被换出!

举一个相关的例子,有一些高性能服务器,它们通过为每个请求创建一个进程,然后在完成后退出该进程来工作。通过这种方式,他们甚至不必跟踪内存分配,也根本不需要进行任何释放或垃圾回收,因为在此过程结束时,一切都将消失在操作系统的空闲内存中。(可以使用自定义内存分配器在进程内完成相同的操作,但需要非常仔细的编程;本质上是在OS进程内制定自己的“轻量级进程”概念。)


11

我很抱歉在此主题的最后发布之后发布了这么长时间。

还有一点。并非所有程序都可以正常退出。崩溃和ctrl-C等将导致程序以不受控制的方式退出。如果您的操作系统没有释放堆,清理堆栈,删除静态变量等,最终将导致系统因内存泄漏或更糟而崩溃。

除了有趣的是,Ubuntu中的崩溃/中断,而且我怀疑所有其他现代OS的确都存在“已处理”资源的问题。套接字,文件,设备等在程序结束/崩溃时可能保持“打开”状态。在正常退出之前,作为清理工作的一部分,使用“句柄”或“描述符”关闭所有内容也是一种很好的做法。

我目前正在开发一个大量使用套接字的程序。当我陷入死机时,我必须从其中退出ctrl-c,从而搁浅我的套接字。我添加了一个std :: vector来收集所有打开的套接字的列表以及捕获sigint和sigterm的sigaction处理程序。处理程序遍历列表并关闭套接字。我计划在抛出异常之前使用类似的清理例程,以免提前终止。

有人愿意对此设计发表评论吗?


1
我很高兴您这么说,因为我有一个程序保留了套接字资源,并且我们的Ubuntu系统每两周需要重新启动一次,否则内存就开始耗尽,并且有足够的内存。如果您忘记清理它们,我不确定系统资源是否已拆除。
octopusgrabbus 2012年

8
Stackoverflow不是论坛。有什么错回答一个老问题。meta.stackexchange.com/questions/20524/reviving-old-questions
mk12 2012年

6

在现代操作系统中,这里发生的是您的程序在其自己的“进程”中运行。这是一个操作系统实体,具有其自己的地址空间,文件描述符等。您的malloc调用是从分配给进程的“堆”或未分配的内存页分配内存。

如本例所示,当程序结束时,分配给进程的所有资源都将由操作系统简单地回收/销毁。对于内存,分配给您的所有内存页面都被简单地标记为“空闲”并被回收以供其他进程使用。页面是比malloc处理的概念更底层的概念-结果,随着整个事情的清理,所有malloc / free的细节都被简单地洗掉了。

这在道德上是等效的,当您用完笔记本电脑并想把它送给朋友时,您不必费心单独删除每个文件。您只需格式化硬盘。

正如所有其他答复者所指出的,所有这些都说明,依靠这种做法不是好习惯:

  1. 您应该始终在编程以照顾资源,而在C中这也意味着内存。您可能最终将代码嵌入库中,或者最终运行时间可能比预期的长得多。
  2. 某些OS(较旧的OS,也许还有一些现代的嵌入式OS)可能无法维持如此严格的进程边界,并且您的分配可能会影响其他OS的地址空间。

4

是。操作系统清理资源。好吧……旧版本的NetWare没有。

编辑:正如San Jacinto所指出的,肯定有一些系统(除了NetWare以外)没有这样做。即使在一次性程序中,我也会养成释放所有资源的习惯,只是为了保持这种习惯。


3
我没有拒绝投票,但这对于后代来说是一个非常危险的职位。DOS仍在许多嵌入式平台上使用,我非常怀疑它会为您执行内存清理。笼统的概括是错误的。
圣哈辛托

@圣哈辛托:这是一个好点。这就是为什么我做了NetWare参考,但它可能需要澄清。我将对其进行一些编辑。
Mark Wilkins'2

3
@San DOS不是多任务操作系统-当DOS程序(不包括TSR)结束时,所有内存都可用于下一个要加载的程序。

@Neil感谢您的提醒,但我指的是类似TSR的程序,该程序将在事件发生时启动,这是嵌入式系统的常见用法。尽管如此,还是感谢您的专业知识和对我失败的地方的澄清:)
San Jacinto 2010年

2

是的,进程结束时,操作系统将释放所有内存。


我不明白为什么这被否决了。进程死后,将释放malloc的内存(malloc的维基百科定义是这样的)
Arve 2010年

7
Wikipedia并不是现有操作系统的手册。 大多数 现代 OS都会回收内存,但并非所有(特别是不是所有旧版本)都可以。除此之外,malloc只能保证C将对内存进行处理。根据设计,C不能保证在C自身以外的行为方面没有任何事情。如果应用程序意外死机,则运行时库发出的所有承诺都是无效的,因为不再履行它们。
cHao 2012年

2

这取决于操作系统通常会为您清除它,但是例如,如果您使用的是嵌入式软件,则可能不会发布。

只需确保将其释放,当您要将其集成到大型项目中时,它可以节省很多时间。


0

这确实取决于操作系统,但是对于您将遇到的所有操作系统,当进程退出时,内存分配将消失。


0

我认为直接释放是最好的。未定义的行为是最糟糕的事情,因此,如果您仍可以在过程中定义它的同时进行访问,那么请这样做,这是有很多充分的理由说明了人们给出的理由。

至于在哪里,或者是否,我发现在W98中,真正的问题是“何时”(我没有看到强调这一点的文章)。一个小型模板程序(用于MIDI SysEx输入,使用各种malloc分配的空间)将释放WndProc的WM_DESTROY位中的内存,但是当我将此移植到较大的程序时,它在退出时崩溃。我以为这意味着我要释放操作系统在较大清理期间已经释放的内容。如果我是在WM_CLOSE上执行的,则称为DestroyWindow(),则一切正常,可以立即退出。

尽管这与MIDI缓冲区不完全相同,但有一个相似之处,就是最好保持过程完整无缺,完全清理然后退出。使用适度的内存块,这非常快。我发现许多小型缓冲区的操作和清理速度要比大型缓冲区少。

正如有人说的那样,可以避免从磁盘上的交换文件中拖出大内存块,但是可能存在例外,但是即使这样,也可以通过保留更多和更小的分配空间来最小化。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.