退出C应用程序时,是否自动释放了malloc-ed内存?

时间:2010-02-06 15:37:22

标签: c memory-management

假设我有以下C代码:

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

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

9 个答案:

答案 0 :(得分:101)

这取决于操作系统。大多数现代(和所有主要)操作系统都会释放程序在结束时无法释放的内存。

依赖于此是不好的做法,最好明确释放它。问题不仅在于您的代码看起来很糟糕。您可能决定将小程序集成到一个较大的,长期运行的程序中。然后一段时间后,你不得不花费数小时追踪内存泄漏 依赖于操作系统的功能也会降低代码的可移植性。

答案 1 :(得分:40)

通常,现代通用操作系统会在终止进程后进行清理。这是必要的,因为替代方案是系统随着时间的推移而丢失资源,并且由于程序写得不好或者只是很少发生泄漏资源的错误而需要重新启动。

由于各种原因,让您的程序明确地释放其资源可能是一种良好的做法,例如:

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

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

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

答案 2 :(得分:7)

我很抱歉在最后一篇帖子发布到这个帖子后很长时间。

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

除此之外,Ubuntu中的崩溃/中断,我怀疑所有其他现代操作系统,确实存在“处理”资源的问题。当程序结束/崩溃时,套接字,文件,设备等可以保持“打开”状态在优雅退出之前,将“手柄”或“描述符”作为清理的一部分,关闭任何东西也是一种好习惯。

我目前正在开发一个大量使用套接字的程序。当我陷入困境时,我必须从中调出ctrl-c,因此,搁置我的插座。我添加了一个std :: vector来收集所有打开的套接字列表和一个捕获sigint和sigterm的sigaction处理程序。处理程序遍历列表并关闭套接字。我计划在抛出前使用类似的清理程序,这将导致提前终止。

有人关心这个设计吗?

答案 3 :(得分:6)

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

当您的程序结束时,如本示例所示,分配给您的流程的所有资源都被操作系统简单地回收/拆除。在内存的情况下,分配给您的所有内存页面都被标记为“空闲”并被回收以供其他进程使用。页面是一个比malloc处理的更低级别的概念 - 因此,当整个事物被清理时,malloc / free的细节都被简单地冲走了。

这是道德等同于,当你完成使用笔记本电脑并希望将它交给朋友时,你不必费心去个别删除每个文件。你只需格式化硬盘。

所有这些都说,正如所有其他回答者所指出的那样,依靠这一点并不是一种好的做法:

  1. 你应该总是编程来处理资源,在C中也意味着内存。您最终可能会将代码嵌入到库中,或者最终运行时间可能会超出预期。
  2. 某些操作系统(较旧的操作系统,可能是一些现代嵌入式系统操作系统)可能无法保持这样的硬处理边界,并且您的分配可能会影响其他人的地址空间。

答案 4 :(得分:4)

是。操作系统清理资源。嗯......旧版本的NetWare没有。

编辑:正如San Jacinto指出的那样,除了NetWare之外,肯定有系统不会这样做。即使在一次性计划中,我也会习惯于释放所有资源,以保持这种习惯。

答案 5 :(得分:2)

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

答案 6 :(得分:2)

这取决于,操作系统通常会为您清理它,但如果您正在处理嵌入式软件,那么它可能不会被释放。

请确保您释放它,以后可能需要将它集成到大型项目中时节省大量时间。

答案 7 :(得分:0)

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

答案 8 :(得分:0)

我认为直接释放是最好的。未定义的行为是最糟糕的事情,因此,如果您在流程中仍然定义了访问权限,那么这样做有很多很好的理由。

关于在哪里,或者是否,我发现在W98中,真正的问题是'何时'(我没有看到帖子强调这一点)。一个小模板程序(用于MIDI SysEx输入,使用各种malloc'd空格)将释放WndProc的WM_DESTROY位中的内存,但是当我将其移植到更大的程序时,它在退出时崩溃。我认为这意味着我试图释放操作系统在更大的清理过程中已经释放的内容。如果我在WM_CLOSE上执行它,然后调用DestroyWindow(),它一切正常,即时清除退出。

虽然这与MIDI缓冲区不完全相同,但有一个相似之处在于最好保持流程完整,完全清理,然后退出。使用适度的内存块,这非常快。我发现许多小缓冲区在操作和清理方面比较少的大缓冲区工作得快。

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

相关问题